home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / What's New? / Development Kits / Mac OS / USB DDK 1.4.6f4 / Examples / PrinterClassDriver / PrinterClassDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-25  |  127.7 KB  |  3,886 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PrinterClassDriver.c
  3.  
  4.     Contains:    MacOS USB printer class driver
  5.                 [ref. IEEE Std 1284-1994]
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9.  
  10.  
  11.     Copyright:    1998 by Apple Computer, Inc., all rights reserved.
  12.  
  13. */
  14.  
  15.  
  16. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  17.     includes
  18.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  19. #include <Gestalt.h>
  20. #include <Devices.h>
  21. #include <DriverServices.h>
  22. #include <Interrupts.h>
  23. #include <LowMem.h>
  24. #include <Folders.h>
  25. #include <String.h>
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <USB.h>
  29.  
  30. #ifndef __CODEFRAGMENTS__
  31. #include <codefragments.h>
  32. #endif
  33.  
  34. #include "PrinterClassDriver.h"
  35. #include "TradDriverLoaderLib.h"
  36.  
  37. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  38.     constants
  39.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  40. #define MAX_SUFFIX                    127                    // maximum copies we'll enter in unit table
  41. #define kUSBParallelDrvrRsrcID        12
  42. #define kMinDrvrUnitNumber            48                    // minimum unit table entry which we'll install
  43. #define kUSS720MillisecondDelay        3*1000                // poll every three seconds
  44. #define kUSS720StatusMSDelay        100                    // poll ten times per second
  45. #define MAX_USB_TRANSFER_SIZE        TRANSFER_SIZE        // zero acts as manifest for conditional compilation
  46.  
  47. #define kUSBAttributeBulk            0x02
  48. #define kUSBInputEndpointMask        0x80
  49.  
  50. #define kDebugStatusLevel            5
  51. #define kNormalStatusLevel            4
  52.  
  53.  
  54. enum
  55. {
  56.     kUSBv12    =    0x01200000,
  57.     kUSBv135 =     0x01350000
  58. };
  59.  
  60. enum
  61. {
  62.     kCString = 0,                // StateStr, USBStatusStr selector
  63.     kPString,                    // StateStr, USBStatusStr selector
  64.     kDrvrFirstDigit = 5            // length_byte + ".USB" = 5
  65. };
  66. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  67.     manifest constants
  68. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  69. //
  70. //    DEBUGGING                        extra debugging information to USB Expert Log
  71. //    DOUBLE_BUFFER                    use a page aligned buffer in system heap to double buffer app i/o
  72. //    LOG                                echo all the write data to a log file in the system folder
  73. // LOCK_MEMORY                        LockMemory on the i/o buffer before write and unlock on write completion
  74. // VIRTUAL_MEMORY_CHECK                check the physical addresses of the buffer we pass for write requests
  75. // MACSBUG_ON_READ                    break into MacsBug before each read request
  76. //    MACSBUG_ON_READ_COMPLETE        break into MacsBug at each read completion routine
  77. //    MACSBUG_ON_WRITE                break into MacsBug on each write request
  78. // MACSBUG_ON_WRITE_COMPLETE        break into MacsBug at each write completion routine
  79. //
  80. #define DEBUGGING                        0    /* DEBUGGING */
  81. #define DOUBLE_BUFFER                    1    /* DOUBLE_BUFFER */
  82. #define LOG                                0    /* LOG */
  83.  
  84. /* As we double buffer into the driver's wired global space, we don't need to lock memory. */
  85. /* If you really want to lock memory you will need to fix Radar #2453091 where an unlock */
  86. /* fails in an error case */
  87. #define LOCK_MEMORY                        0    /* LOCK_MEMORY */
  88. #if LOCK_MEMORY
  89. #if DOUBLE_BUFFER
  90. #error "LOCK_MEMORY is not necessary with DOUBLE_BUFFER
  91. #endif
  92. #error "If you turn on lock memory you need to fix the error case where its not unlocked"
  93. #endif
  94.  
  95. #define MACSBUG_ON_READ                    0    /* MACSBUG_ON_READ */
  96. #define MACSBUG_ON_READ_COMPLETE        0    /* MACSBUG_ON_READ_COMPLETE */ 
  97. #define MACSBUG_ON_WRITE                0    /* MACSBUG_ON_WRITE */
  98. #define MACSBUG_ON_WRITE_COMPLETE        0    /* MACSBUG_ON_WRITE_COMPLETE */ 
  99. #define VIRTUAL_MEMORY_CHECK            0    /* VIRTUAL_MEMORY_CHECK requires LOCK_MEMORY */
  100.  
  101. #if LOG
  102. #define LOGGING(x)    x
  103. #include <stdio.h>
  104. #else
  105. #define LOGGING(x)
  106. #endif
  107.  
  108. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  109.     globals
  110.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  111. static struct usbPrinterPBStruct    printerClassRecord;
  112. static FSSpec                            printerClassDriverFileSpec;
  113. LOGGING( static FILE                    *logfile );
  114.  
  115. SInt16    openRef = 0;        // used to only suspend on last close
  116.  
  117. volatile enum{
  118.     kUSBPrintSuspended,
  119.     kUSBPrintResumed
  120.     }wantToBe = kUSBPrintResumed, currentlyAre = kUSBPrintResumed;
  121.  
  122. // These for resuming reads, writes and control calls which were delayed due to resume
  123.  
  124. IOParamPtr Wpb; DCtlPtr Wctl; struct usbPrinterPBStruct *WpPrinterPB;
  125. IOParamPtr Rpb; DCtlPtr Rctl; struct usbPrinterPBStruct *RpPrinterPB;
  126. IOParamPtr Cpb; DCtlPtr Cctl; struct usbPrinterPBStruct *CpPrinterPB;
  127.  
  128. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  129.     prototypes
  130.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  131.  
  132. static void    PrinterDeviceCompletionProc(USBPB *pb);
  133. static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
  134. static void    SoftReset( USBPB *usbprint, short interfaceNum );
  135. static void    ClearEndpointHalt( USBPB *usbprint);
  136. static void    CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
  137. static void    CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
  138. static void CompletionProc(USBPB *pb);
  139. static OSStatus MyUSBExpertStatusLevel(UInt32 level, USBDeviceRef ref, StringPtr status, UInt32 value);
  140.  
  141. void            PrinterDeviceInitiateTransaction(USBPB *pb);
  142.  
  143. OSErr            CFMInitialization( CFragInitBlock *initBlock );
  144.  
  145. Boolean        gUSBVersionNeedsBulkFixPresent;
  146. UInt32        gUSBVersion;
  147.  
  148. void        CheckUSBVersion(void);
  149. OSStatus     SecondaryUSBBulkRead(void *pb, void *result);
  150. OSStatus     SecondaryUSBBulkWrite(void *pb, void *result);
  151. OSStatus     SafeUSBBulkRead(USBPB *pb);
  152. OSStatus     SafeUSBBulkWrite(USBPB *pb);
  153.  
  154. void    CheckUSBVersion(void)
  155. {
  156. OSStatus    err;
  157.  
  158.     err = Gestalt('usbv', (long*)&gUSBVersion);
  159.     if (err == noErr)
  160.         gUSBVersionNeedsBulkFixPresent = (gUSBVersion < kUSBv12);
  161. }
  162.  
  163. OSStatus SecondaryUSBBulkRead(void *pb, void *result)
  164. {
  165.     *(OSStatus*)result = USBBulkRead((USBPB*)pb);
  166.     return noErr;
  167. }
  168.  
  169. OSStatus SecondaryUSBBulkWrite(void *pb, void *result)
  170. {
  171.     *(OSStatus*)result = USBBulkWrite((USBPB*)pb);
  172.     return noErr;
  173. }
  174.  
  175. OSStatus SafeUSBBulkRead(USBPB *pb)
  176. {
  177.     OSStatus    result;
  178.  
  179.     pb->usbFlags = 0;    // BT we may have set the address request flag
  180.     if (gUSBVersionNeedsBulkFixPresent)
  181.     {
  182.         // Use CallSecondaryInterruptHandler2 to call USBBulkRead if
  183.         // less than USB v1.2 present
  184.         CallSecondaryInterruptHandler2(SecondaryUSBBulkRead, nil, pb, &result);
  185.     }
  186.     else
  187.         result = USBBulkRead(pb);
  188.         
  189.     return result;
  190. }
  191.  
  192. OSStatus SafeUSBBulkWrite(USBPB *pb)
  193. {
  194.     OSStatus    result;
  195.  
  196.     pb->usbFlags = 0;    // BT we may have set the address request flag
  197.     if (gUSBVersionNeedsBulkFixPresent)
  198.     {
  199.         // Use CallSecondaryInterruptHandler2 to call USBBulkWrite if
  200.         // less than USB v1.2 present
  201.         CallSecondaryInterruptHandler2(SecondaryUSBBulkWrite, nil, pb, &result);
  202.     }
  203.     else
  204.         result = USBBulkWrite(pb);
  205.         
  206.     return result;
  207. }
  208.  
  209.  
  210.  
  211.  
  212. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  213.     Name:        HexString8
  214.  
  215.     Input Parameters:    
  216.         v                unsigned long value
  217.         
  218.     Output Parameters:
  219.         p                8 bytes: hex string representing value
  220.         
  221.     Description:
  222.  
  223.  
  224.  
  225. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  226. static void
  227. HexString8( unsigned long v, unsigned char *p )
  228. {
  229.     short    shift;
  230.     
  231.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  232.     {
  233.         char c = (v >> shift) & 0x0F;
  234.         *p++ = c + (c > 9? ('A'-10): '0');
  235.     }
  236. }
  237.  
  238. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  239.     Name:        hexstr
  240.  
  241.     Input Parameters:    
  242.         count                number of bytes
  243.         p                    pointer to bytes
  244.         
  245.     Output Parameters:
  246.         q                    hex dump of data
  247.         
  248.     Description:
  249.  
  250.  
  251.  
  252. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  253. void hexstr( long count, char *p, char *q )
  254. {
  255.     char *s = p;
  256.     long i = count;
  257.     for ( ; count > 0; --count, ++p )
  258.     {
  259.         UInt8 hi, lo;
  260.         hi = (*p >> 4)& 0x0F;
  261.         lo = *p & 0x0F;
  262.         *q++ = '0';
  263.         *q++ = 'x';
  264.         *q++ = hi + (hi > 9? 'A' - 10: '0');
  265.         *q++ = lo + (lo > 9? 'A' - 10: '0');
  266.         *q++ = ' ';
  267.     }
  268.     for ( ; i > 0; --i, ++s )
  269.         *q++ = *s < ' ' || *s > 0x7E? '.': *s;
  270. }
  271.  
  272. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  273.     Name:        ForceUpperStr
  274.  
  275.     Input Parameters:    
  276.         s                    pointer to a null terminated string
  277.         
  278.     Output Parameters:
  279.         s                    string modified by using toupper() on each character.
  280.         
  281.     Description:
  282.  
  283.  
  284.  
  285.  
  286. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  287. void 
  288. ForceUpperStr(char *s)
  289. {
  290.     while(*s){
  291.         *s = toupper(*s);
  292.         s++;
  293.     }
  294. }
  295.     
  296. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  297.     Name:        MakeNameRegistrySafeStr
  298.  
  299.     Input Parameters:    
  300.         s                    pointer to a null terminated string
  301.         
  302.     Output Parameters:
  303.         s                    string modified by replacing / with - on each character.
  304.         
  305.     Description:
  306.  
  307.  
  308.  
  309. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  310. void 
  311. MakeNameRegistrySafeStr(char *s)
  312. {
  313.     while (*s)
  314.     {
  315.         if (*s == '/') 
  316.             *s = '-';
  317.         s++;
  318.     }
  319. }
  320.  
  321.  
  322.  
  323. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  324.     Name:        USBStatusStr
  325.  
  326.     Input Parameters:    
  327.         usbStatus            usb error code
  328.         kind                    kPString or kCString
  329.         
  330.     Output Parameters:
  331.         unsigned char *    description of error (c-string or p-string)
  332.  
  333.     Description:
  334.         a simple mapping of errors to human-readable form
  335.  
  336.  
  337.  
  338.  
  339.  
  340. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  341. static unsigned char *
  342. USBStatusStr( OSStatus usbStatus, short kind )
  343. {
  344.     unsigned char *p;
  345.  
  346.     switch ( usbStatus )
  347.     {
  348.         case    kUSBInternalErr:                    p = kPStrPrinterDriverName"Internal error"; break;
  349.         case    kUSBUnknownDeviceErr:                p = kPStrPrinterDriverName"Unknown device"; break;
  350.         case    kUSBUnknownPipeErr:                 p = kPStrPrinterDriverName"Unknown pipe"; break;
  351.         case    kUSBTooManyPipesErr:                p = kPStrPrinterDriverName"Too many pipes"; break;
  352.         case    kUSBIncorrectTypeErr:                p = kPStrPrinterDriverName"Incorrect type"; break;
  353.         case    kUSBRqErr:                            p = kPStrPrinterDriverName"Request error"; break;
  354.         case    kUSBUnknownRequestErr:                p = kPStrPrinterDriverName"Unknown request"; break;
  355.         case    kUSBTooManyTransactionsErr:            p = kPStrPrinterDriverName"Too many transactions"; break;
  356.         case    kUSBAlreadyOpenErr:                    p = kPStrPrinterDriverName"Already open"; break;
  357.         case    kUSBNoDeviceErr:                    p = kPStrPrinterDriverName"No device"; break;
  358.         case    kUSBDeviceErr:                        p = kPStrPrinterDriverName"Device error"; break;
  359.         case    kUSBOutOfMemoryErr:                    p = kPStrPrinterDriverName"Out of memory"; break;
  360.         case    kUSBNotFound:                        p = kPStrPrinterDriverName"Not found"; break;
  361.         case    kUSBPBVersionError:                    p = kPStrPrinterDriverName"Wrong pbVersion"; break;
  362.         case    kUSBPBLengthError:                    p = kPStrPrinterDriverName"pbLength too small"; break;
  363.         case    kUSBCompletionError:                p = kPStrPrinterDriverName"Missing completion routine"; break;
  364.         case    kUSBFlagsError:                        p = kPStrPrinterDriverName"Unused flags not zeroed"; break;
  365.         case    kUSBAbortedError:                    p = kPStrPrinterDriverName"Pipe aborted"; break;
  366.         case    kUSBNoBandwidthError:                p = kPStrPrinterDriverName"No bandwidth available"; break;
  367.         case    kUSBPipeIdleError:                    p = kPStrPrinterDriverName"Pipe is idle"; break;
  368.         case    kUSBPipeStalledError:                p = kPStrPrinterDriverName"Pipe is stalled"; break;
  369.         case    kUSBUnknownInterfaceErr:            p = kPStrPrinterDriverName"Unknown interfaceRef"; break;
  370.         case    kUSBDeviceBusy:                        p = kPStrPrinterDriverName"Device is busy"; break;
  371.         case    kUSBDevicePowerProblem:                p = kPStrPrinterDriverName"Device power problem"; break;
  372.         case    kUSBInvalidBuffer:                    p = kPStrPrinterDriverName"Bad buffer (nil?)"; break;
  373.         case    kUSBDeviceSuspended:                p = kPStrPrinterDriverName"Device is suspended"; break;
  374.         case    kUSBDeviceNotSuspended:                p = kPStrPrinterDriverName"Device is not suspended"; break;
  375.         case    kUSBDeviceDisconnected:                p = kPStrPrinterDriverName"Disconnected during suspend/reset"; break;
  376.         case    kUSBTimedOut:                        p = kPStrPrinterDriverName"Transaction timed out"; break;
  377.  
  378.         case    kUSBLinkErr:                        p = kPStrPrinterDriverName"Link Err"; break;
  379.         case    kUSBCRCErr:                            p = kPStrPrinterDriverName"Comms/Device err, bad CRC";  break;        
  380.         case    kUSBBitstufErr:                        p = kPStrPrinterDriverName"Comms/Device err, bitstuffing"; break;        
  381.         case    kUSBDataToggleErr:                    p = kPStrPrinterDriverName"Comms/Device err, Bad data toggle"; break;        
  382.         case    kUSBEndpointStallErr:                p = kPStrPrinterDriverName"Device didn't understand"; break;        
  383.         case    kUSBNotRespondingErr:                p = kPStrPrinterDriverName"No device, device hung"; break;        
  384.         case    kUSBPIDCheckErr:                    p = kPStrPrinterDriverName"Comms/Device err, PID CRC error"; break;        
  385.         case    kUSBWrongPIDErr:                    p = kPStrPrinterDriverName"Comms/Device err, Bad or wrong PID"; break;        
  386.         case    kUSBOverRunErr:                        p = kPStrPrinterDriverName"Packet too large or more data than buffer"; break;        
  387.         case    kUSBUnderRunErr:                    p = kPStrPrinterDriverName"Less data than buffer"; break;        
  388.         case    kUSBRes1Err:                        p = kPStrPrinterDriverName"kUSBRes1Err"; break;        
  389.         case    kUSBRes2Err:                        p = kPStrPrinterDriverName"kUSBRes1Err"; break;        
  390.         case    kUSBBufOvrRunErr:                    p = kPStrPrinterDriverName"Buffer over run error"; break;        
  391.         case    kUSBBufUnderRunErr:                    p = kPStrPrinterDriverName"Buffer under run error"; break;        
  392.         case    kUSBNotSent1Err:                    p = kPStrPrinterDriverName"Transaction not sent1"; break;        
  393.         case    kUSBNotSent2Err:                    p = kPStrPrinterDriverName"Transaction not sent2"; break;    
  394.         default:
  395.             p = kPStrPrinterDriverName"Unknown error nnnnnnnn";
  396.             HexString8( usbStatus, p + *p - 8 + 1 );
  397.             break;
  398.     }
  399.     
  400.     return kind == kPString? p: p + 1;
  401. }
  402.  
  403. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  404.     Name:        StateStr
  405.  
  406.     Input Parameters:    
  407.         usbRefCon            usb error code
  408.         kind                    kPString or kCString
  409.         
  410.     Output Parameters:
  411.         unsigned char *    description of state (c-string or p-string)
  412.  
  413.     Description:
  414.         a simple mapping of states to human-readable form
  415.  
  416.  
  417.  
  418.  
  419.  
  420. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  421. static unsigned char *
  422. StateStr( OSStatus refCon, short kind )
  423. {
  424.     unsigned char *p;
  425.  
  426.     refCon &= ~(kTransactionPending | kRetryTransaction | kReturnFromDriver);
  427.     switch ( refCon )
  428.     {
  429.         case kUndefined:                            p = kPStrPrinterDriverName"kUndefined"; break;
  430.         case kNilCompletion:                        p = kPStrPrinterDriverName"kNilCompletion"; break;
  431.  
  432.         case kFindInterface_bidirectional:            p = kPStrPrinterDriverName"kFindInterface_bidirectional"; break;
  433.         case kFindInterface_unidirectional:            p = kPStrPrinterDriverName"kFindInterface_unidirectional"; break;
  434.         case kOpenDevice:                            p = kPStrPrinterDriverName"kOpenDevice"; break;
  435.         case kNewInterfaceRef:                        p = kPStrPrinterDriverName"kNewInterfaceRef"; break;
  436.  
  437.         case kSetInterface:                            p = kPStrPrinterDriverName"kSetInterface"; break;
  438.         case kConfigureInterface:                    p = kPStrPrinterDriverName"kConfigureInterface"; break;
  439.         case kGetCapabilityString:                    p = kPStrPrinterDriverName"kGetCapabilityString"; break;
  440.         case kDelayGetCapability:                    p = kPStrPrinterDriverName"kDelayGetCapability"; break;
  441.  
  442.         case kAllocateCapabilityMem:                p = kPStrPrinterDriverName"kAllocateCapabilityMem"; break;
  443.         case kGetFullCapabilityString:                p = kPStrPrinterDriverName"kGetFullCapabilityString"; break;
  444.         case kGetInterface:                            p = kPStrPrinterDriverName"kGetInterface"; break;
  445.         case kFindBulkOutPipe:                        p = kPStrPrinterDriverName"kFindBulkOutPipe"; break;
  446.  
  447.         case kFindBulkInPipe:                        p = kPStrPrinterDriverName"kFindBulkInPipe"; break;
  448.         case kTaskTimeRequired:                        p = kPStrPrinterDriverName"kTaskTimeRequired"; break;
  449.  
  450.         case kGetCentronicsStatus:                    p = kPStrPrinterDriverName"kGetCentronicsStatus"; break;
  451.         case kDelayGetCentronicsStatus:                p = kPStrPrinterDriverName"kDelayGetCentronicsStatus"; break;
  452.  
  453.         case kDeallocateCapbilityString:            p = kPStrPrinterDriverName"kDeallocateCapbilityString"; break;
  454.         default:
  455.             p = kPStrPrinterDriverName"Unknown state nnnnnnnn";
  456.             HexString8( refCon, p + *p - 8 + 1 );
  457.             break;
  458.     }
  459.     return kind == kPString? p: p + 1;    
  460. }
  461.  
  462. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  463.     Name:        HiHex
  464.  
  465.     Input Parameters:    
  466.         v                        only low byte used
  467.         
  468.     Output Parameters:
  469.         <function result>    high nibble represented as ASCII char
  470.         
  471.     Description:
  472.  
  473.  
  474.  
  475. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  476. static unsigned char
  477. HiHex( unsigned char v )
  478. {
  479.     unsigned char    hinibble = (v >> 4) & 0x0f;
  480.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  481. }
  482.  
  483. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  484.     Name:        LoHex
  485.  
  486.     Input Parameters:    
  487.         v                        only low byte used
  488.         
  489.     Output Parameters:
  490.         <function result>    low nibble represented as ASCII char
  491.         
  492.     Description:
  493.  
  494.  
  495.  
  496. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  497. static unsigned char
  498. LoHex( unsigned char v )
  499. {
  500.     unsigned char    lonibble = v & 0x0f;
  501.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  502. }
  503.  
  504. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  505.     Name:        immediateError
  506.  
  507.     Input Parameters:    
  508.         
  509.     Output Parameters:
  510.         
  511.     Description:
  512.  
  513.  
  514.  
  515. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  516. static Boolean
  517. immediateError(OSStatus err)
  518. {
  519.     return((err != kUSBPending) && (err != noErr) );
  520. }
  521.  
  522. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  523.     Name:        SetNullUSBParamBlock
  524.  
  525.     Input Parameters:    
  526.         pb                    pointer to USB parameter block
  527.         dev                USB device reference
  528.     Output Parameters:
  529.         pb                    all fields set to default values
  530.  
  531.     Description:
  532.         setup a USB parameter block for use by the current device
  533.  
  534.  
  535.  
  536.  
  537. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  538. static void
  539. SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
  540. {
  541.     pb->qlink = NULL;
  542.     pb->qType = 0;
  543.     pb->pbLength = sizeof(USBPB);
  544.     pb->pbVersion = kUSBCurrentPBVersion;
  545.     pb->usbFlags = 0;
  546.     pb->usbStatus = noErr;
  547.     pb->usbCompletion = (USBCompletion) NULL;
  548.  
  549.     pb->usbReference = dev;
  550. }
  551.  
  552. // BT - 15Jun99, Callback for the suspend call.
  553. static void usbPrintResume(USBPB *pb)
  554. {
  555. IOParamPtr resumePB;
  556. DCtlPtr resumeCtl;
  557. struct usbPrinterPBStruct *resumePrinterPB;
  558.  
  559.     if(pb->usbStatus != noErr)
  560.     {
  561.         MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, "\pUSB print driver USBPrintDoSuspendResume error", pb->usbStatus);
  562.     }
  563.     else
  564.     {
  565.         currentlyAre = kUSBPrintResumed;
  566.         if(Wpb != nil)
  567.         {
  568.             // We have to restart a waiting write
  569.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, "\pUSB print driver resumeing write", 0);
  570.             resumeCtl = Wctl;
  571.             resumePrinterPB = WpPrinterPB;
  572.             resumePB = Wpb;
  573.             Wpb = nil;
  574.             QueueWrite(resumePB, resumeCtl, resumePrinterPB);
  575.         }
  576.     
  577.         if(Rpb != nil)
  578.         {
  579.             // We have to restart a waiting write
  580.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, "\pUSB print driver resumeing read", 0);
  581.             resumeCtl = Rctl;
  582.             resumePrinterPB = RpPrinterPB;
  583.             resumePB = Rpb;
  584.             Rpb = nil;
  585.             QueueRead(resumePB, resumeCtl, resumePrinterPB);
  586.         }
  587.         if(Cpb != nil)
  588.         {
  589.             // We have to restart a waiting ControlRequest
  590.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, "\pUSB print driver resumeing read", 0);
  591.             resumeCtl = Cctl;
  592.             resumePrinterPB = CpPrinterPB;
  593.             resumePB = Cpb;
  594.             Cpb = nil;
  595.             ControlStatusRequests(resumePB, resumeCtl, resumePrinterPB);
  596.         }
  597.     }
  598.     pb->usbRefcon = 0;
  599. }
  600.  
  601. // BT - 15Jun99, work out if we need to and can suspend or resume and do it.
  602. static USBPrintDoSuspendResume(USBDeviceRef ref)
  603. {
  604. static USBPB pb;
  605. OSStatus err = noErr;
  606.     if(wantToBe != currentlyAre)
  607.     {
  608.         if(currentlyAre == kUSBPrintSuspended)
  609.         {
  610.             MyUSBExpertStatusLevel(kDebugStatusLevel, ref, "\pUSB print driver resuming device", ref);
  611.             err = USBResumeDeviceByReference(ref);
  612.         }
  613.         else if(wantToBe == kUSBPrintSuspended)
  614.         {
  615.             if( (printerClassRecord.pb.usbCompletion != nil) || 
  616.                 (printerClassRecord.in.usbCompletion != nil) || 
  617.                 (printerClassRecord.out.usbCompletion != nil) )
  618.             {
  619.                 MyUSBExpertStatusLevel(kDebugStatusLevel, ref, "\pUSB print driver can't suspend, busy", (UInt32) printerClassRecord.pb.usbCompletion);
  620.                 return(noErr);
  621.             }
  622.         
  623.             if(pb.usbRefcon != 0)
  624.             {
  625.                 MyUSBExpertStatusLevel(kDebugStatusLevel, ref, "\pUSB print driver suspend already in process", err);
  626.                 return(noErr);
  627.             }
  628.             MyUSBExpertStatusLevel(kDebugStatusLevel, ref, "\pUSB print driver suspending device", ref);
  629.             SetNullUSBParamBlock(ref, &pb);
  630.             pb.usbCompletion = usbPrintResume;
  631.             pb.usbRefcon = 1;
  632.             currentlyAre = kUSBPrintSuspended;
  633.             err = USBSuspendDevice(&pb);
  634.         }
  635.         if( (err != kUSBPending) && (err != noErr) )
  636.         {
  637.             MyUSBExpertStatusLevel(2, ref, "\pUSB print driver USBPrintDoSuspendResume error", err);
  638.         }
  639.     }
  640.     return(noErr);
  641. }
  642.  
  643.  
  644.  
  645.  
  646.  
  647. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  648.     Name:        ParseCapability
  649.  
  650.     Input Parameters:    
  651.         capability            pointer to 1284-1994 capability string
  652.         attribute            pointer to c-string key we're retrieving (terminate with colon)
  653.         *result_length        maximum length of the result 
  654.         
  655.     Output Parameters:
  656.         result                c-string which followed the key and was terminated by semi-colon
  657.                                 (semi-colon has been stripped)
  658.         *result_length        actual length of the result (may be zero)
  659.     
  660.     Description:
  661.         Search for "attribute" in the 1284 "capability" string
  662.         The identifier is terminated with a semi-colon
  663.  
  664.         Return the attribute in result
  665.             null-string if attribute not found.
  666.  
  667.  
  668.  
  669.  
  670.  
  671. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  672. static void
  673. ParseCapability(
  674.     unsigned char    *capability,
  675.     unsigned char    *attribute,
  676.     unsigned char    *result,
  677.     short            *result_length 
  678. )
  679. {
  680.     //
  681.     //    search for "attribute" in the 1284 "capability" string
  682.     //
  683.     //    the identifier is terminated with a semi-colon
  684.     //
  685.     //    return the attribute in result
  686.     //            null-string if attribute not found
  687.     //
  688.     //    <to do> skip blanks, isolate colon, skip blanks
  689.     //
  690.     UInt32                source_length;
  691.     UInt16                target_length;
  692.     unsigned char        *source,
  693.                         *target,
  694.                         *destination;
  695.     Boolean                foundAttribute = false;
  696.     
  697.     //
  698.     //    begin a brute force search
  699.     //
  700.     source = attribute;
  701.     source_length = CStrLen((char *)attribute );
  702.  
  703.     target = capability + 2;    // skip the length
  704.     target_length =  *(UInt16*)capability;
  705.     if (target_length >= 2)
  706.         target_length -= 2;            // don't count the length
  707.     else
  708.         target_length = 0;
  709.         
  710.     while ( target_length >= source_length )
  711.     {
  712.         if ( memcmp( source, target, source_length ) == 0 ){
  713.             foundAttribute = true;
  714.             break;
  715.         }
  716.         --target_length;
  717.         ++target;
  718.     }
  719.     
  720.     *result = '\0';    // empty result
  721.  
  722.     if (foundAttribute)  // we found the attribute string we are looking for, let's copy the result
  723.     {
  724.         destination = result;
  725.     
  726.         target += source_length;
  727.         target_length -= source_length;    // skip the attribute string
  728.     
  729.         if ( target_length > 0 )
  730.         {
  731.             //
  732.             //    we found the attribute in the capability string
  733.             //
  734.             while ( destination - result < *result_length )    // arbitrarily limit reply
  735.             {
  736.                 if ( *target == ';' || target_length == 0)
  737.                     break;
  738.                 *destination++ = *target++;        // copy a byte of attribute over
  739.                 --target_length;
  740.             }
  741.             *destination++ = '\0';                        // trailing NUL
  742.             *result_length = destination - result;    // report the length of the data (with trailing NUL)
  743.         }
  744.     }
  745. }
  746.  
  747.  
  748. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  749.     Name:        GetClass
  750.  
  751.     Input Parameters:    
  752.         capability            pointer to 1284-1994 capability string
  753.         *result_length        maximum length of the result 
  754.         
  755.     Output Parameters:
  756.         result                c-string extracted from the MODEL key
  757.         *result_length        actual length of the result  (may be zero)
  758.         
  759.     Description:
  760.         CLASS is a Microsoft extension to the 1284-capability string
  761.         if we don't find it
  762.             we assume that the device is a printer
  763.         Since the USB hardware has already indicated this, we're really allowing
  764.         devices which aren't printers to be reached via the DRVRs we've installed.
  765.  
  766.  
  767.  
  768.  
  769. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  770. static void
  771. GetClass(
  772.     unsigned char    *capability,
  773.     unsigned char    *result,
  774.     short            *result_length
  775. )
  776. {
  777.     //
  778.     //    We supply the upper-case PRINTER to be consistent with 1284-1994
  779.     //        if we don't find a class.
  780.     //
  781.     ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
  782.     if ( *result == '\0' )
  783.         ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
  784.     if ( *result == '\0' )
  785.         CStrCopy( (char *)result, "PRINTER" );
  786. }
  787.  
  788.  
  789. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  790.     Name:        GetModel
  791.  
  792.     Input Parameters:    
  793.         capability            pointer to 1284-1994 capability string
  794.         *result_length        maximum length of the result 
  795.         
  796.     Output Parameters:
  797.         result                c-string extracted from the MODEL key
  798.         *result_length        actual length of the result  (may be zero)
  799.             
  800.     Description:
  801.         MODEL is a required field of the 1284-capability string
  802.         MODEL may be abbreviated MDL
  803.  
  804.  
  805.  
  806.  
  807. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  808. static void
  809. GetModel(
  810.     unsigned char    *capability, 
  811.     unsigned char    *result,
  812.     short            *result_length
  813. )
  814. {
  815.     //
  816.     //    Most manufacturers abbreviate, so we search for MDL first
  817.     //
  818.     ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
  819.     if ( *result == '\0' )
  820.         ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
  821. }
  822.  
  823.  
  824. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  825.     Name:        GetCommandSet
  826.  
  827.     Input Parameters:    
  828.         
  829.     Output Parameters:
  830.         
  831.     Description:
  832.  
  833.  
  834.  
  835.  
  836. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  837. static void
  838. GetCommandSet(
  839.     unsigned char    *capability, 
  840.     unsigned char    *result,
  841.     short              *result_length
  842. )
  843. {
  844.     //
  845.     //    COMMAND-SET is a required field of the 1284-capability string
  846.     //    COMMAND-SET may be abbreviated CMD
  847.     //
  848.     ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
  849.     if ( *result == '\0' )
  850.         ParseCapability( capability, (unsigned char *) "COMMAND SET:", result, result_length );
  851. }
  852.  
  853. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  854.     Name:        GetManufacturer
  855.  
  856.     Input Parameters:    
  857.         
  858.     Output Parameters:
  859.         
  860.     Description:
  861.  
  862.  
  863.  
  864. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  865. static void
  866. GetManufacturer(
  867.     unsigned char *capability, 
  868.     unsigned char *result,
  869.     short *result_length
  870. )
  871. {
  872.     //
  873.     //    MANUFACTURER is a required field of the 1284-capability string
  874.     //    MANUFACTURER may be abbreviated MFG
  875.     //
  876.     ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
  877.     if ( *result == '\0' )
  878.         ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
  879.     if ( *result == '\0' )
  880.         ParseCapability( capability, (unsigned char *) "HMFG:", result, result_length );
  881. }
  882.  
  883.  
  884. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  885.     Name:        DeregisterDevice
  886.  
  887.     Input Parameters:    
  888.         pPrinterPB
  889.  
  890.     Output Parameters:
  891.         <none>
  892.         
  893.     Description:
  894.         remove the device from the name registry
  895.  
  896.  
  897.  
  898.  
  899.  
  900. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  901. #define kMinNameLength    27
  902. #define kMinModelLength    25
  903. #define kMinClassLength    23
  904.  
  905. static OSStatus
  906. DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  907. {
  908. RegEntryID            self, child, parent;
  909. RegEntryIter         cookie;
  910.  
  911. OSStatus    err = noErr;
  912. Str255        tempStr1,tempStr2;
  913. UInt32        nameLength, modelLength,devclassLength;
  914. Boolean     done = false;
  915.  
  916.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Removing the printer from the name registry", 0 );
  917.     // delete the printer node
  918.     // print out the printer's name (which is the same as the node name)
  919.     nameLength = CStrLen((char *)pPrinterPB->name);
  920.     CStrCopy((char *)tempStr1, (char *)(kCStrPrinterDriverName"Printer name:  "));
  921.     CStrCat((char *)tempStr1, (char *)pPrinterPB->name);
  922.     CStrToPStr((unsigned char *)tempStr2, (char *)tempStr1 );
  923.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, tempStr2, nameLength );
  924.     
  925.     // locate the model node (parent of printer), and delete it if the printer has no siblings
  926.     if (nameLength<kMinNameLength)
  927.     {
  928.         USBExpertFatalError(pPrinterPB->deviceRef, err, kPStrPrinterDriverName"Warning!! Printer name string is not long enough!", nameLength);
  929.     }
  930.     else
  931.     {
  932.         RegistryEntryIDInit( &self );
  933.         err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  934.         if ( err == noErr )
  935.         {    
  936.             err = RegistryEntryDelete( &self);
  937.         }
  938.         else
  939.         {
  940.             MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Printer node not found!", err );
  941.         }
  942.         RegistryEntryIDDispose(&self);
  943.         
  944.     }
  945.  
  946.  
  947.     // print out the printer's model (which is the same as the node's parent)
  948.     modelLength = CStrLen((char *)pPrinterPB->model);
  949.     CStrCopy((char *)tempStr1, (char *)(kCStrPrinterDriverName"Printer model: "));
  950.     CStrCat((char *)tempStr1, (char *)pPrinterPB->model);
  951.     CStrToPStr((unsigned char *)tempStr2, (char *)tempStr1 );
  952.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, tempStr2, modelLength );
  953.     
  954.  
  955.     // locate the model node (parent of printer), and delete it if the printer has no siblings
  956.     if (modelLength<kMinModelLength)
  957.     {
  958.         USBExpertFatalError(pPrinterPB->deviceRef, err, kPStrPrinterDriverName"Warning!! Printer model string is not long enough!", modelLength);
  959.     }
  960.     else
  961.     {
  962.         RegistryEntryIDInit( &parent );
  963.         err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->model , &parent );
  964.         if ( err == noErr )
  965.         {    
  966.             RegistryEntryIDInit(&child);
  967.             
  968.             err = RegistryEntryIterateCreate(&cookie);
  969.             if (err == noErr)
  970.                 err = RegistryEntryIterateSet(&cookie, &parent);
  971.             if (err == noErr)
  972.                 err = RegistryEntryIterate(&cookie, kRegIterChildren, &child, &done);
  973.             if ((err == noErr) && done)
  974.             {
  975.                 MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"No siblings detected, so delete the parent of printer", 0 );
  976.                 err = RegistryEntryDelete(&parent);
  977.             }
  978.             else
  979.             {
  980.                 MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Siblings (or error) detected.  Leaving parent in place", err );
  981.             }
  982.             RegistryEntryIterateDispose(&cookie);
  983.         }
  984.         else
  985.         {
  986.             MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Parent node not found!", err );
  987.         }
  988.         RegistryEntryIDDispose(&parent);
  989.     }
  990.     
  991.     // print out the printer's model (which is the same as the node's parent)
  992.     devclassLength = CStrLen((char *)pPrinterPB->devclass);
  993.     CStrCopy((char *)tempStr1, (char *)(kCStrPrinterDriverName"Printer class: "));
  994.     CStrCat((char *)tempStr1, (char *)pPrinterPB->devclass);
  995.     CStrToPStr((unsigned char *)tempStr2, (char *)tempStr1 );
  996.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, tempStr2, devclassLength );
  997.     
  998.  
  999.     // locate the class node (parent of model), and delete it if the class has no siblings
  1000.     if (devclassLength<kMinClassLength)
  1001.     {
  1002.         USBExpertFatalError(pPrinterPB->deviceRef, err, kPStrPrinterDriverName"Warning!! Printer class string not long enough!", devclassLength);
  1003.     }
  1004.     else
  1005.     {
  1006.         RegistryEntryIDInit( &parent );
  1007.         err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->devclass , &parent );
  1008.         if ( err == noErr )
  1009.         {    
  1010.             RegistryEntryIDInit(&child);
  1011.             
  1012.             err = RegistryEntryIterateCreate(&cookie);
  1013.             if (err == noErr)
  1014.                 err = RegistryEntryIterateSet(&cookie, &parent);
  1015.             if (err == noErr)
  1016.                 err = RegistryEntryIterate(&cookie, kRegIterChildren, &child, &done);
  1017.             if ((err == noErr) && done)
  1018.             {
  1019.                 MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"No models found, so delete the class node", 0 );
  1020.                 err = RegistryEntryDelete(&parent);
  1021.             }
  1022.             else
  1023.             {
  1024.                 MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Models detected.  Leaving class nodes in place", err );
  1025.             }
  1026.             RegistryEntryIterateDispose(&cookie);
  1027.         }
  1028.         else
  1029.         {
  1030.             MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Parent node not found!", err );
  1031.         }
  1032.         RegistryEntryIDDispose(&parent);
  1033.     }
  1034.     
  1035.     return err;
  1036. }
  1037.  
  1038. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1039.     Name:        RegisterDevice
  1040.  
  1041.     Input Parameters:    
  1042.         pPrinterPB
  1043.  
  1044.     Output Parameters:
  1045.         <none>
  1046.         
  1047.     Description:
  1048.         add the device into the name registry; we can't insert just the node
  1049.         if the parent nodes aren't present.
  1050.  
  1051.         if it isn't present
  1052.             insert the device CLASS into the registry
  1053.         if it isn't present
  1054.             insert the device MODEL into the registry
  1055.         finally insert the device itself into the registry
  1056.             we're careful to rename multiple devices
  1057.  
  1058.  
  1059.  
  1060.  
  1061.  
  1062.  
  1063.  
  1064.  
  1065.  
  1066. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1067. static OSStatus
  1068. RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  1069. {
  1070.     //
  1071.     //    add the device into the name registry
  1072.     //    if it isn't present
  1073.     //        insert the device CLASS into the registry
  1074.     //    if it isn't present
  1075.     //        insert the device MODEL into the registry
  1076.     //    finally insert the device itself into the registry
  1077.     //        we're careful to rename multiple devices
  1078.     //
  1079. Str255        identification,
  1080.                 devclass,
  1081.                 model,
  1082.                 nameregmodel,
  1083.                 commands,
  1084.                 tempstr;
  1085.                 
  1086. RegEntryID    parent, where, self;
  1087.  
  1088. OSStatus        err;
  1089.  
  1090. short            model_length,
  1091.                 command_length,
  1092.                 class_length;
  1093.  
  1094.  
  1095.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Adding the printer to the name registry", 0 );
  1096.     CStrCopy((char *)pPrinterPB->devclass, "");
  1097.     CStrCopy((char *)pPrinterPB->model, "");
  1098.     CStrCopy((char *)pPrinterPB->name, "");
  1099.  
  1100.     command_length = sizeof(commands);
  1101.     GetCommandSet(pPrinterPB->pCapabilityString, commands, &command_length );
  1102.  
  1103.  
  1104.     // get device class and add it to the name registry.  Typically PRINTER or Printer
  1105.     class_length = sizeof(devclass);
  1106.     GetClass( pPrinterPB->pCapabilityString, devclass, &class_length );
  1107.     // force the device class to all uppercase.
  1108.     ForceUpperStr((char *)devclass);
  1109.     
  1110.     CStrCopy( (char *)pPrinterPB->devclass, (char *)"Devices:device-tree:" );
  1111.     CStrCat( (char *)pPrinterPB->devclass, (char *)devclass );
  1112.     
  1113.     RegistryEntryIDInit( &where );
  1114.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->devclass, &where );
  1115.     if ( err == nrPathNotFound ) 
  1116.     {
  1117.         //    class not in registry
  1118.         //        create a node for all devices of this CLASS
  1119.         //
  1120.         RegistryEntryIDInit( &parent );
  1121.         err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
  1122.         if ( err == noErr )
  1123.             err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->devclass, &where );
  1124.         RegistryEntryIDDispose(&parent);
  1125.  
  1126.     }
  1127.     
  1128.     CStrToPStr(tempstr, (char *)pPrinterPB->devclass);
  1129.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, tempstr, 0 );
  1130.     
  1131.     //
  1132.     //    add this model into the name registry of this class
  1133.     //
  1134.     if ( err == noErr )
  1135.     {
  1136.         model_length = sizeof(model);
  1137.         GetModel( pPrinterPB->pCapabilityString, model, &model_length );
  1138.         CStrCopy( (char *)nameregmodel, (char *)model);
  1139.         MakeNameRegistrySafeStr((char *)nameregmodel);
  1140.         if ( *model != '\0' )
  1141.         {
  1142.             CStrCopy( (char *)pPrinterPB->model, "Devices:device-tree:" );
  1143.             CStrCat( (char *)pPrinterPB->model, (char *)devclass );
  1144.             CStrCat( (char *)pPrinterPB->model, ":" );
  1145.             if ( *model == '\0'  )
  1146.             {
  1147.                 CStrCat( (char *)pPrinterPB->model, (char *)"USB_PRINTERCLASS" );
  1148.             }
  1149.             else
  1150.             {
  1151.                 CStrCat( (char *)pPrinterPB->model, (char *)nameregmodel );
  1152.             }
  1153.             RegistryEntryIDInit( &self );
  1154.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->model , &self );
  1155.             if ( err != noErr )
  1156.             {
  1157.                 // model not in registry
  1158.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->model, &self );
  1159.             }
  1160.             
  1161.             RegistryEntryIDDispose(&self);
  1162.         }
  1163.         CStrToPStr(tempstr, (char *)pPrinterPB->model);
  1164.         MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, tempstr, 0 );
  1165.     }
  1166.     
  1167.     //
  1168.     //    add this instance of this model of this class
  1169.     //        into the name registry
  1170.     //
  1171.     if ( *model == '\0'  )
  1172.     {
  1173.         //
  1174.         //    possibly the cable isn't firmly connected or the printer isn't switched on
  1175.         //
  1176.         err = kUSBInternalErr;
  1177.         USBExpertFatalError(pPrinterPB->deviceRef, err, kPStrPrinterDriverName"Model undefined", 0);
  1178.     }
  1179.     if ( err == noErr )
  1180.     {
  1181.         //
  1182.         //    start off by identifying the device simply by the model name
  1183.         //        increment the numeric suffix until we successfully registry the device
  1184.         //
  1185.         Str32    suffix;
  1186.         short    numeric_suffix;
  1187.  
  1188.         CStrCopy( (char *)identification, (char *)nameregmodel );
  1189.         RegistryEntryIDInit( &self );
  1190.         for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
  1191.         {
  1192.             CStrCopy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  1193.             CStrCat( (char *)pPrinterPB->name, (char *)devclass );
  1194.             CStrCat( (char *)pPrinterPB->name, ":" );
  1195.             CStrCat( (char *)pPrinterPB->name, (char *)nameregmodel );
  1196.             CStrCat( (char *)pPrinterPB->name, ":" );
  1197.             CStrCat( (char *)pPrinterPB->name, (char *)identification );
  1198.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  1199.             if ( err != noErr )
  1200.             {
  1201.                 // enter device in registry
  1202.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  1203.                 if ( err == noErr )
  1204.                 {
  1205.                     CStrCopy( (char *)identification, (char *)model );
  1206.                     if (numeric_suffix > 1)
  1207.                     {
  1208.                         sprintf( (char *)suffix, " %d", numeric_suffix-1 );
  1209.                         CStrCat( (char *)identification, (char *)suffix );
  1210.                     }
  1211.                     err = RegistryPropertyCreate( &self, "modelName", identification, strlen((char *)identification) );
  1212.                 }
  1213.                 if ( err == noErr )
  1214.                     err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
  1215.                 if ( err == noErr )
  1216.                     err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
  1217.                 
  1218.                 if (pPrinterPB->printerProtocol != kUSBPrinterUnidirectionalProtocol)
  1219.                 {
  1220.                     if ( err == noErr )
  1221.                         err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
  1222.                     if ( err == noErr )
  1223.                         err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
  1224.                 }
  1225.                 if ( err == noErr )
  1226.                     err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
  1227.                 if ( err == noErr )
  1228.                     err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
  1229.                 if ( err == noErr )
  1230.                     err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
  1231.                 if ( err == noErr && *commands != '\0' )
  1232.                     err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
  1233.                 break;
  1234.             }
  1235.             //
  1236.             //    if this name didn't succeed
  1237.             //        try the next numeric suffix
  1238.             //
  1239.             sprintf( (char *)suffix, " %d", numeric_suffix );
  1240.             CStrCopy( (char *)identification, (char *)nameregmodel );
  1241.             CStrCat( (char *)identification, (char *)suffix );
  1242.         }
  1243.         RegistryEntryIDDispose(&self);
  1244.     }
  1245.     pPrinterPB->printerRegistered = true;
  1246.     
  1247.     CStrToPStr((unsigned char *)tempstr, (char const *)pPrinterPB->name );
  1248.     
  1249.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Added printer to name registry", 0 );
  1250.     MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, tempstr, err );
  1251.     RegistryEntryIDDispose(&where);
  1252.  
  1253.     LOGGING( logfile = fopen( "USBPrinter.log", "wb+" ) );
  1254.     return err;
  1255. }
  1256.  
  1257. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1258.     Name:        LoadResources
  1259.  
  1260.     Input Parameters:
  1261.         pPrinterPB            pointer to class driver's private storage
  1262.         
  1263.     Output Parameters:
  1264.         OSStatus                resource load error
  1265.         
  1266.     Description:
  1267.         Initialize time is the only safe time to to load resources from our file.
  1268.         Here's where we load resources and detach them from the resource manager.
  1269.         Later we'll use these private copies instead of GetResource calls.
  1270.         
  1271.         Using the file spec that we got from the CFMInitialization routine, open
  1272.         our resource fork.
  1273.  
  1274.  
  1275.  
  1276.  
  1277. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1278. static OSStatus
  1279. LoadResources( struct usbPrinterPBStruct *pPrinterPB )
  1280. {
  1281.     short            rf = -1;                // class driver resource fork
  1282.     OSStatus        err;
  1283.  
  1284.     //
  1285.     //    open the resource fork of this class driver
  1286.     //
  1287.     rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
  1288.     err = ResError();
  1289.     
  1290.     //
  1291.     //    load the DRVR that we'll stick in the unit table
  1292.     //
  1293.     pPrinterPB->hDrvr = NULL;
  1294.     if ( err == noErr )
  1295.     {
  1296.         pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR',  kUSBParallelDrvrRsrcID );
  1297.         if ( pPrinterPB->hDrvr != NULL )
  1298.             DetachResource( (Handle) pPrinterPB->hDrvr );
  1299.         err = ResError();
  1300.     }
  1301.     
  1302.     if ( rf != -1 )
  1303.         CloseResFile( rf );
  1304.     
  1305.     return err;
  1306. }
  1307.  
  1308. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1309.     Name:        InstallDrivers
  1310.  
  1311.     Input Parameters:
  1312.         pPrinterPB
  1313.         
  1314.     Output Parameters:
  1315.         OSStatus            error code
  1316.         
  1317.     Description:
  1318.         install read and write drivers in the unit table
  1319.             we have separate drivers so that we can support a full-duplex protocol
  1320.         rename the driver we just installed (so multiple copies don't conflict)
  1321.         We use the DRVR -refnum-1 so that the driver name has the same hex chars
  1322.             as the driver number (for manual verification in MacsBug)
  1323.  
  1324.  
  1325.  
  1326.  
  1327.  
  1328.  
  1329. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1330. static OSStatus
  1331. InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
  1332. {
  1333.     //
  1334.     //    install the driver in the unit table
  1335.     //    rename the driver we just installed (so multiple copies don't conflict)
  1336.     //    
  1337.     short            refNum;                // DRVR refNum
  1338.     OSStatus        err =  paramErr;    // couldn't find driver
  1339.  
  1340.     if ( pPrinterPB->hDrvr != NULL )
  1341.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
  1342.  
  1343.     if ( err == noErr )
  1344.     {
  1345.         UnitNumber        unit;
  1346.         DriverFlags        flags;
  1347.         DRVRHeaderPtr    hdr;
  1348.         unsigned char    *suffix,        // append "In" and "Out"
  1349.                             *infix;        // driver reference number follows the ".USB"
  1350.  
  1351.         TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
  1352.         BlockMoveData( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
  1353.         
  1354.         suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
  1355.         infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
  1356.         infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
  1357.         infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
  1358.         suffix[0] = 'O';
  1359.         suffix[1] = 'u';
  1360.         suffix[2] = 't';
  1361.         TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
  1362.         //
  1363.         //    set the driver data to point to our parameter block
  1364.         //
  1365.         err = OpenDriver( pPrinterPB->driverOutName, &refNum );
  1366.         if ( err == noErr )
  1367.         {
  1368.             struct usbPrinterPBStruct *param = pPrinterPB;
  1369.             err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1370.             CloseDriver( refNum );
  1371.         }
  1372.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
  1373.         if ( err == noErr )
  1374.         {
  1375.             
  1376.             suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
  1377.             infix = pPrinterPB->driverInName + kDrvrFirstDigit;
  1378.             infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
  1379.             infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
  1380.             suffix[0] = 'I';
  1381.             suffix[1] = 'n';
  1382.             TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
  1383.             //
  1384.             //    set the driver data to point to our parameter block
  1385.             //
  1386.             err = OpenDriver( pPrinterPB->driverInName, &refNum );
  1387.             if ( err == noErr )
  1388.             {
  1389.                 struct usbPrinterPBStruct *param = pPrinterPB;
  1390.                 err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1391.                 CloseDriver( refNum );
  1392.             }
  1393.         }
  1394.     }
  1395.     
  1396.     return err;
  1397. }
  1398.  
  1399. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1400.     Name:        GetCapability
  1401.  
  1402.     Input Parameters:    
  1403.         
  1404.     Output Parameters:
  1405.         
  1406.     Description:
  1407.         Asynchronous completion.
  1408.  
  1409.  
  1410.  
  1411. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1412. static void
  1413. GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, short length )
  1414. {
  1415.     //
  1416.     //    queue a transaction to retrieve the 1284 capability string
  1417.     //        we must have assigned the interface by this point since the capability string
  1418.     //        may vary with the interface
  1419.     //
  1420.     OSStatus        err;
  1421.     USBPB            *pb = &pPrinterPB->pb;
  1422.  
  1423.     SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  1424.     
  1425.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1426.     pb->usbBuffer = 0;
  1427.     pb->usbActCount = 0;
  1428.     pb->usbReqCount = 0;
  1429.  
  1430.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  1431.     pb->usb.cntl.WValue = 0;            // configuration
  1432.     pb->usb.cntl.WIndex = (pPrinterPB->interfaceNumber<<8) | pPrinterPB->alternateSetting;
  1433.  
  1434.     pb->usbReqCount = length;
  1435.     pb->usbBuffer = p;
  1436.  
  1437.     pb->usbRefcon |= kTransactionPending;
  1438.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1439.     err = USBDeviceRequest(pb);
  1440.     if(immediateError(err))
  1441.     {
  1442.         USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"GetCapability", 0);
  1443.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1444.         pb->usbRefcon |= kReturnFromDriver;
  1445.     }
  1446. }
  1447.  
  1448. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1449.     Name:        IsLucentCable
  1450.  
  1451.     Input Parameters:    
  1452.         dev            USB device descriptor
  1453.         
  1454.     Output Parameters:
  1455.         Return 1 if the USB device is a USB-parallel cable
  1456.         
  1457.     Description:
  1458.         
  1459.  
  1460.  
  1461.  
  1462. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1463. static short
  1464. IsLucentCable( USBDeviceDescriptor    *dev )
  1465. {
  1466.     return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
  1467. }
  1468.  
  1469.  
  1470. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1471.     Name:        GetInterface
  1472.  
  1473.     Input Parameters:    
  1474.         
  1475.     Output Parameters:
  1476.         
  1477.     Description:
  1478.         Asynchronous completion.
  1479.  
  1480.  
  1481.  
  1482. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1483. static void
  1484. GetInterface( USBPB *pb, UInt8 *alt )
  1485. {
  1486.     //
  1487.     //    make sure we account for any alternate interface currently in use by the device
  1488.     //
  1489.     OSStatus    err;
  1490.  
  1491.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  1492.  
  1493.     pb->usb.cntl.BRequest = kUSBRqGetInterface;
  1494.     pb->usb.cntl.WValue = 0; 
  1495.     pb->usb.cntl.WIndex = 0;
  1496.  
  1497.     pb->usbReqCount = sizeof(UInt8);        // single byte is requested
  1498.     pb->usbBuffer = alt;
  1499.  
  1500.     pb->usbStatus = 0;
  1501.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1502.     pb->usbRefcon |= kTransactionPending;
  1503.  
  1504.     err = USBDeviceRequest(pb);
  1505.     if(immediateError(err))
  1506.     {
  1507.         USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"GetInterface", 0);
  1508.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1509.         pb->usbRefcon |= kReturnFromDriver;
  1510.     }
  1511. }
  1512.  
  1513.  
  1514. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1515.     Name:        ReadCompletion
  1516.  
  1517.     Input Parameters:    
  1518.         pb                        USB parameter block
  1519.         
  1520.     Output Parameters:
  1521.         <none>
  1522.  
  1523.     Description:
  1524.         USB read requests complete here.
  1525.         We dequeue the MacOS DRVR read requests
  1526.  
  1527.  
  1528.  
  1529.  
  1530.  
  1531.  
  1532.  
  1533.  
  1534. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1535. static void
  1536. ReadCompletion(USBPB *pb)
  1537. {
  1538.     //    call the user completion routine
  1539.     struct usbPrinterPBStruct
  1540.             *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1541.     IOParamPtr     clientParam = pPrinterPB->readDrvr.pb;
  1542.     OSStatus        err = pb->usbStatus;
  1543.     DCtlPtr            ctlLocal;
  1544.  
  1545. #if MACSBUG_ON_READ_COMPLETE
  1546.     Str255    text;
  1547.     sprintf( (char *)text, " PrinterClass Read Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1548.     text[0] = CStrLen((char *)text); // c2pstr
  1549.     DebugStr( text );
  1550. #endif
  1551.  
  1552. #if DOUBLE_BUFFER
  1553.     //
  1554.     //    copy the user data from our page aligned buffer
  1555.     //
  1556.     MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"ReadCompletion - bytes read  " , (UInt32)pb->usbActCount );
  1557.  
  1558.     if ( pb->usbActCount > 0 )
  1559.         BlockCopy( pPrinterPB->pageReadAlignedBuffer, clientParam->ioBuffer + clientParam->ioActCount, pb->usbActCount );
  1560. #endif
  1561.     //    update the amount of data actually transferred
  1562.     clientParam->ioActCount += pb->usbActCount;
  1563.  
  1564.     switch( pb->usbStatus )
  1565.     {
  1566.         //
  1567.         //    only retry low level hardware problems
  1568.         //        note: abort transactions will end up here as well
  1569.         //
  1570.     case kUSBLinkErr:
  1571.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1572.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1573.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1574.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1575.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1576.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1577.         if (  --(pPrinterPB->readRetryCount) >= 0 ) // = is there so we don't retry clear endpoints forever
  1578.         {
  1579.             if(pPrinterPB->readStatus == noErr)
  1580.             {
  1581.                 pPrinterPB->readStatus = pb->usbStatus;
  1582.             }
  1583.             // we got an error, and we still want to retry, clear any stalls
  1584.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"ReadCompletion retry" , pb->usbStatus );
  1585.             USBClearPipeStallByReference(pPrinterPB->readPipeRef);
  1586.             pb->usbStatus = noErr;
  1587.  
  1588.             
  1589.             MyUSBExpertStatusLevel(3, pb->usbReference, kPStrPrinterDriverName"**** ReadCompletion clearing endpoint halt *****" , pb->usbStatus );
  1590.             ClearEndpointHalt(pb);    // Sets up PB
  1591.             USBDeviceRequest(pb);
  1592.             return;
  1593.         }
  1594.         break;
  1595.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1596.         MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"ReadCompletion abortedError" , pb->usbStatus );
  1597.         // This is useless, an abort does not stall the pipe
  1598.         USBClearPipeStallByReference(pPrinterPB->readPipeRef);
  1599.         USBClearPipeStallByReference(pPrinterPB->deviceRef);
  1600.         break;
  1601.         //
  1602.         //    any other error will be reported to the client
  1603.         //
  1604.     default:
  1605.     case noErr:
  1606.         break;
  1607.     }
  1608.     
  1609. //    (pPrinterPB->readStatus != noErr)    
  1610. //or 
  1611. //    (pPrinterPB->readStatus == noErr) and (pb->usbActCount == pb->usbReqCount)
  1612.  
  1613. //                  read Status == noErr
  1614. //                     true        false
  1615. //
  1616. //  act=req  t      r         r
  1617. //
  1618. //           f      x         r
  1619.  
  1620.     
  1621.     if ( (pb->usbStatus == noErr) &&                                 // there were no problems
  1622.          (pPrinterPB->readRetryCount > 0) &&                        // there were no enough problems
  1623.          
  1624.         ( (pPrinterPB->readStatus != noErr) ||
  1625.          (pb->usbActCount == pb->usbReqCount)  ) &&                    // we got all the data we requested
  1626. // BT don't do this or we'll never retry read errors. However we need to do this to finish short packets.
  1627. //  
  1628.  
  1629.         (clientParam->ioActCount < clientParam->ioReqCount) )        // we still want more data
  1630.     {
  1631.         //
  1632.         //    haven't finish the client's request
  1633.         //        update the pointers and start another bulk read transaction
  1634.         //
  1635. #if LOCK_MEMORY
  1636.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1637.         IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"ReadCompletion UnlockMem failed" ) );
  1638. #endif
  1639.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1640.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1641. #if MAX_USB_TRANSFER_SIZE
  1642.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1643.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1644. #endif
  1645. #if DOUBLE_BUFFER
  1646.         //
  1647.         //    make sure we have enough room in our buffer
  1648.         //
  1649.         if ( pb->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1650.             pb->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1651.         pb->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1652. #endif
  1653.  
  1654.         pPrinterPB->readStatus = noErr;
  1655. #if LOCK_MEMORY
  1656.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1657.         IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"ReadCompletion LockMem failed" ) );
  1658.         if ( err == noErr )
  1659. #endif
  1660.             err = SafeUSBBulkRead( pb );    // Note this is probably hanging off the if above.
  1661.         if ( immediateError(err) )
  1662.         {
  1663.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"ReadCompletion finish immed err" , err );
  1664.  
  1665.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1666.             if ( pPrinterPB->readDrvr.ctl != NULL )
  1667.             {
  1668.                 ctlLocal = pPrinterPB->readDrvr.ctl;
  1669.                 pPrinterPB->readDrvr.ctl = NULL;
  1670.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1671.             }
  1672.         }
  1673.     }
  1674.     else
  1675.     {
  1676.         if(pPrinterPB->readStatus != noErr)
  1677.         {
  1678.             pb->usbStatus = pPrinterPB->readStatus;
  1679.         }
  1680.         //
  1681.         //        either we have an error which we're not retrying
  1682.         //            or we successfully completed
  1683.         //
  1684. #if LOCK_MEMORY
  1685.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1686.         IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"ReadCompletion concluded UnlockMem failed" ) );
  1687. #endif
  1688.         IF_DEBUG( if (pb->usbStatus != noErr) MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"ReadCompletion Error" , pb->usbStatus ) );
  1689.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1690.         MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"readDrvr.ctl = " , (UInt32)pPrinterPB->readDrvr.ctl );
  1691.         if ( pPrinterPB->readDrvr.ctl != NULL )
  1692.         {
  1693.             ctlLocal = pPrinterPB->readDrvr.ctl;
  1694.             pPrinterPB->readDrvr.ctl = NULL;
  1695.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal); 
  1696.         }
  1697.         else
  1698.         {
  1699.             IF_DEBUG( DebugStr( kPStrPrinterDriverName"ReadCompletion() pPrinterPB->readDrvr.ctl == NULL" ) );
  1700.         }
  1701.         MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, "\pUSB PRint, read completion do suspend resume" , pb->usbReference);
  1702.         USBPrintDoSuspendResume(pPrinterPB->interfaceRef);
  1703.     }
  1704. }
  1705.  
  1706.  
  1707. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1708.     Name:        WriteCompletion
  1709.  
  1710.     Input Parameters:    
  1711.         pb                        USB parameter block
  1712.         
  1713.     Output Parameters:
  1714.         <none>
  1715.  
  1716.     Description:
  1717.         USB write requests complete here.
  1718.         We dequeue the MacOS DRVR write requests
  1719.  
  1720.         when breaking up transactions we use ioActCount to determine how much remains 
  1721.                 of the original request and where the next request begins
  1722.         if we've failed with a USB error
  1723.             usbActCount indicates how much data has been transferred with the current request
  1724.             and if the retry count hasn't been exceeded
  1725.                 we proceed as if we'd just requested that much in this transactions
  1726.         note the retry count is cumulative for the original client request
  1727.             not for each usb transaction
  1728.  
  1729.  
  1730.  
  1731.  
  1732.  
  1733.  
  1734.  
  1735.  
  1736.  
  1737.  
  1738. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1739. static void
  1740. WriteCompletion(USBPB *pb)
  1741. {
  1742.     //    call the user completion routine
  1743.     struct usbPrinterPBStruct
  1744.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1745.     IOParamPtr     clientParam = pPrinterPB->writeDrvr.pb;
  1746.     DCtlPtr            ctlLocal;
  1747.     OSStatus        err = pb->usbStatus;
  1748.  
  1749. #if MACSBUG_ON_WRITE_COMPLETE
  1750.     Str255    text;
  1751.     sprintf( (char *)text, " PrinterClass Write Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1752.     text[0] = CStrLen((char *)text); // c2pstr
  1753.     DebugStr( text );
  1754. #endif
  1755.  
  1756.     //    update the amount of data actually transferred
  1757.     clientParam->ioActCount += pb->usbActCount;
  1758.     MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"WriteCompletion - bytes written  " , (UInt32)pb->usbActCount);
  1759.  
  1760.     switch( pb->usbStatus )
  1761.     {
  1762.         //
  1763.         //    only retry low level hardware problems
  1764.         //        note: abort transactions will end up here as well
  1765.         //
  1766.     case kUSBLinkErr:
  1767.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1768.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1769.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1770.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1771.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1772.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1773.         if (  --(pPrinterPB->writeRetryCount) >= 0 ) // = is there so we don't retry clearendpoints forever
  1774.         {
  1775.             if(pPrinterPB->writeStatus == noErr)
  1776.             {
  1777.                 pPrinterPB->writeStatus = pb->usbStatus;
  1778.             }
  1779.             // we got an error, and we still want to retry, clear any stalls
  1780.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"WriteCompletion retry" , pb->usbStatus );
  1781.             USBClearPipeStallByReference(pPrinterPB->writePipeRef);
  1782.             pb->usbStatus = noErr;
  1783.             
  1784.             MyUSBExpertStatusLevel(3, pb->usbReference, kPStrPrinterDriverName"**** WriteCompletion clearing endpoint halt *****" , pb->usbStatus );
  1785.             ClearEndpointHalt(pb);    // Sets up PB
  1786.             USBDeviceRequest(pb);
  1787.             return;
  1788.             
  1789.         }
  1790.         break;
  1791.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1792.         // This is useless, an abort does not stall the pipe
  1793.         USBClearPipeStallByReference(pPrinterPB->writePipeRef);
  1794.         USBClearPipeStallByReference(pPrinterPB->deviceRef);
  1795.         break;
  1796.         //
  1797.         //    any other error will be reported to the client
  1798.         //
  1799.     default:
  1800.     case noErr:
  1801.         break;
  1802.     }
  1803.  
  1804.     if ( (pPrinterPB->writeRetryCount > 0) && 
  1805.          (pb->usbStatus == noErr) &&
  1806.          (clientParam->ioActCount < clientParam->ioReqCount) )
  1807.     {
  1808.         //
  1809.         //    haven't finish the client's request
  1810.         //        update the pointers and start another bulkOut transaction
  1811.         //
  1812. #if LOCK_MEMORY
  1813.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1814.         IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"WriteCompletion UnlockMem failed" ) );
  1815. #endif
  1816.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1817.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1818. #if MAX_USB_TRANSFER_SIZE
  1819.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1820.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1821. #endif
  1822. #if DOUBLE_BUFFER
  1823.         //
  1824.         //    make sure we have enough room in our buffer
  1825.         //    then copy the user data into our page aligned buffer
  1826.         //
  1827.         if ( pb->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1828.             pb->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1829.             
  1830.         BlockCopy( pb->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, pb->usbReqCount );
  1831.         pb->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1832.         
  1833. #endif
  1834.  
  1835.  
  1836.         pPrinterPB->writeStatus = noErr;
  1837. #if LOCK_MEMORY
  1838.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1839.         IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"WriteCompletion LockMem failed" ) );
  1840.         if ( err == noErr )
  1841. #endif
  1842.             err = SafeUSBBulkWrite( pb );    // Note this is probably hanging off the if above.
  1843.         if ( immediateError(err) )
  1844.         {
  1845.             MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"WriteCompletion finish immed err" , err );
  1846.  
  1847.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1848.             if ( pPrinterPB->writeDrvr.ctl != NULL )
  1849.             {
  1850.                 ctlLocal = pPrinterPB->writeDrvr.ctl;
  1851.                 pPrinterPB->writeDrvr.ctl = NULL;
  1852.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1853.             }
  1854.         }
  1855.     }
  1856.     else
  1857.     {
  1858.         if(pPrinterPB->writeStatus != noErr)
  1859.         {
  1860.             pb->usbStatus = pPrinterPB->writeStatus;
  1861.         }
  1862.         //
  1863.         //        either we have an error which we're not retrying
  1864.         //            or we successfully completed
  1865.         //
  1866. #if LOCK_MEMORY
  1867.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1868.         IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"WriteCompletion concluded UnlockMem failed" ) );
  1869. #endif
  1870.  
  1871.         IF_DEBUG( if (pb->usbStatus != noErr) MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"WriteCompletion Error" , pb->usbStatus ) );
  1872.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1873.  
  1874.  
  1875.         MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, kPStrPrinterDriverName"writeDrvr.ctl = " , (UInt32)pPrinterPB->writeDrvr.ctl );
  1876.         if ( pPrinterPB->writeDrvr.ctl != NULL )
  1877.         {
  1878.             ctlLocal = pPrinterPB->writeDrvr.ctl;
  1879.             pPrinterPB->writeDrvr.ctl = NULL;
  1880.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal ); 
  1881.         }
  1882.         else
  1883.         {
  1884.             IF_DEBUG( DebugStr( kPStrPrinterDriverName"WriteCompletion() pPrinterPB->writeDrvr.ctl == NULL" ) );
  1885.         }
  1886.         MyUSBExpertStatusLevel(kDebugStatusLevel, pb->usbReference, "\pUSB PRint, write completion do suspend resume" , pb->usbReference );
  1887.         
  1888.         if (gUSBVersion >= kUSBv135)
  1889.         {
  1890.             USBPrintDoSuspendResume(pPrinterPB->interfaceRef);
  1891.         }
  1892.     }
  1893. }
  1894.  
  1895. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1896.     Name:        QueueRead
  1897.  
  1898.     Input Parameters:    
  1899.         pb                        MacOS device manager parameter block
  1900.         ctl                    device manager dCtl block
  1901.         pPrinterPB            current printing device class's storage
  1902.         
  1903.     Output Parameters:
  1904.         <none>
  1905.  
  1906.     Description:
  1907.         MacOS DRVR read requests are re-queued here to the USB
  1908.         Since we only allow one read request pending at a time, we're able
  1909.         to use the USB refCon to point to our class driver's storage.
  1910.  
  1911.  
  1912.  
  1913.  
  1914. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1915. void
  1916. QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1917. {    
  1918.     OSStatus    err;
  1919.     USBPB        *usbprint = &pPrinterPB->in;
  1920.     
  1921. #if MACSBUG_ON_READ
  1922.     Str255    text;
  1923.  
  1924.     sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1925.     text[0] = CStrLen((char *)text); // c2pstr
  1926.     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, text, usbprint->usbStatus );
  1927.     DebugStr( text );
  1928. #endif
  1929.  
  1930.     // BT - 15Jun99, if we're not currently awake, delay this until we are.
  1931.     if(currentlyAre == kUSBPrintSuspended)
  1932.     {
  1933.         pb->ioResult = ioInProgress;
  1934.         MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, delaying read for resume", 0 );
  1935.         RpPrinterPB = pPrinterPB;
  1936.         Rctl = ctl;
  1937.         Rpb = pb;
  1938.         if( (currentlyAre != kUSBPrintSuspended) && (Rpb != nil) )
  1939.         {
  1940.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, resumed while we wern't looking", 0 );
  1941.             // resumed and executed this while we were doing this.
  1942.             return;
  1943.         }
  1944.         else
  1945.         {
  1946.             // now wait for resume to happen
  1947.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, let resume take over", 0 );
  1948.             return;
  1949.         }        
  1950.     }
  1951.  
  1952.  
  1953.     pb->ioActCount = 0;        // nothing transfered yet
  1954.     if ( pPrinterPB->terminating )
  1955.         pb->ioResult = abortErr;
  1956.     else
  1957.     {
  1958.  
  1959.         pPrinterPB->readRetryCount = 5;
  1960.         pPrinterPB->readStatus = noErr;
  1961.         pPrinterPB->readDrvr.pb= pb;
  1962.         pPrinterPB->readDrvr.ctl = ctl;
  1963.         if (( pPrinterPB->readPipeRef != NULL ) && (pPrinterPB->printerConfigured))
  1964.         {
  1965.             SetNullUSBParamBlock( pPrinterPB->readPipeRef,  usbprint );
  1966.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, kPStrPrinterDriverName"Set up to do bulk read", pb->ioReqCount );
  1967.             usbprint->usbActCount = 0;
  1968.             usbprint->usbBuffer = pb->ioBuffer;
  1969.             usbprint->usbReqCount = pb->ioReqCount;
  1970.  
  1971. #if MAX_USB_TRANSFER_SIZE
  1972.             //
  1973.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1974.             //        or there is an error which can't be retried
  1975.             //
  1976.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1977.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1978. #endif
  1979. #if DOUBLE_BUFFER
  1980.             //
  1981.             //    make sure we have enough room in our buffer
  1982.             //    then copy the user data into our page aligned buffer
  1983.             //
  1984.             if ( usbprint->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1985.                 usbprint->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1986.             usbprint->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1987. #endif
  1988.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1989.             usbprint->usbCompletion = (USBCompletion) ReadCompletion;
  1990.             
  1991.             pb->ioResult = ioInProgress;
  1992. #if LOCK_MEMORY
  1993.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1994.             IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"QueueRead LockMem failed" ) );
  1995.             if ( err == noErr )
  1996. #endif
  1997.             err = SafeUSBBulkRead( usbprint );
  1998.             if ( immediateError(err) )
  1999.             {
  2000.                 MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, kPStrPrinterDriverName"Error doing bulk read",err );
  2001.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  2002.                 usbprint->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  2003.                 pb->ioResult = err;
  2004.             }
  2005.         }
  2006.         else
  2007.         {
  2008.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, kPStrPrinterDriverName"Read to unopened pipe" , usbprint->usbStatus ) ;
  2009.             pb->ioResult = abortErr;
  2010.         }
  2011.     }
  2012. }
  2013.  
  2014. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2015.     Name:        QueueWrite
  2016.  
  2017.     Input Parameters:    
  2018.         pb                        MacOS device manager parameter block
  2019.         ctl                    device manager dCtl block
  2020.         pPrinterPB            current printing device class's storage
  2021.         
  2022.     Output Parameters:
  2023.         <none>
  2024.  
  2025.     Description:
  2026.         MacOS DRVR write requests are re-queued here to the USB
  2027.         Since we only allow one read request pending at a time, we're able
  2028.         to use the USB refCon to point to our class driver's storage.
  2029.  
  2030.  
  2031.  
  2032. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2033. void
  2034. QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  2035. {
  2036.     OSStatus    err;
  2037.     USBPB        *usbprint = &pPrinterPB->out;
  2038. #if VIRTUAL_MEMORY_CHECK
  2039.     //
  2040.     //    dump the VM table
  2041.     //
  2042.     Str255                        text;
  2043.     LogicalToPhysicalTable        *vmTable;
  2044.     MemoryBlock                    *physical;
  2045.     unsigned long                vmCount,
  2046.                                 vmEntry,
  2047.                                 vmTblLength;
  2048. #endif
  2049.  
  2050. #if MACSBUG_ON_WRITE
  2051.     Str255    text;
  2052.     sprintf( (char *)text, " "kCStrPrinterDriverName"%d @ %08x", pb->ioReqCount, pb->ioBuffer );
  2053.     text[0] = CStrLen((char *)text); // c2pstr
  2054.     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, text, usbprint->usbStatus );
  2055.     DebugStr( text );
  2056. #endif
  2057.  
  2058.     // BT - 15Jun99, if we're not currently awake, delay this until we are.
  2059.     if(currentlyAre == kUSBPrintSuspended)
  2060.     {
  2061.         pb->ioResult = ioInProgress;
  2062.         MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, delaying write for resume", 0 );
  2063.  
  2064.         WpPrinterPB = pPrinterPB;
  2065.         Wctl = ctl;
  2066.         Wpb = pb;
  2067.         if( (currentlyAre != kUSBPrintSuspended) && (Wpb != nil) )
  2068.         {
  2069.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, resumed while we wern't looking", 0 );
  2070.             // resumed and executed this while we were doing this.
  2071.         }
  2072.         else
  2073.         {
  2074.             // now wait for resume to happen
  2075.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, let resume take over", 0 );
  2076.             return;
  2077.         }        
  2078.     }
  2079.  
  2080.  
  2081.  
  2082. #if VIRTUAL_MEMORY_CHECK
  2083.     //
  2084.     //    this check current won't compile without runtime error: need to lock memory, but lock has moved
  2085.     //
  2086.     sprintf( (char *)text, " "kCStrPrinterDriverName"Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  2087.     text[0] = CStrLen((char *)text); // c2pstr
  2088.     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, text, usbprint->usbStatus );
  2089.     
  2090.     vmCount = 127;
  2091.     vmTblLength = (vmCount+1)*sizeof(MemoryBlock);
  2092.     vmTable = (LogicalToPhysicalTable *) NewPtrSys( vmTblLength );
  2093.     LockMemory( vmTable, vmTblLength );
  2094.     LockMemory( &vmCount, sizeof(unsigned long) );
  2095.     vmTable->logical.address = pb->ioBuffer;
  2096.     vmTable->logical.count = pb->ioReqCount;
  2097.     err = GetPhysical( vmTable, &vmCount );
  2098.     
  2099.     if ( err == noErr )
  2100.     {
  2101.         for ( vmEntry = 0, physical = &vmTable->physical[0]; vmEntry < vmCount; ++vmEntry , ++physical)
  2102.         {
  2103.             sprintf( (char *)text, " "kCStrPrinterDriverName"Write: VM @%08x (%d)", physical->address, physical->count );
  2104.             text[0] = CStrLen((char *)text); // c2pstr
  2105.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, text, usbprint->usbStatus );
  2106.         }
  2107.     }
  2108.     UnlockMemory( vmTable, vmTblLength );
  2109.     UnlockMemory( &vmCount, sizeof(unsigned long) );
  2110. #endif
  2111.     pb->ioActCount = 0;        // nothing transfered yet
  2112.  
  2113.  
  2114.     usbprint->usbStatus = noErr;    // forget about abort and things from previous writes
  2115.     if ( pPrinterPB->terminating )
  2116.         pb->ioResult = abortErr;
  2117.     else
  2118.     {
  2119.         pPrinterPB->writeRetryCount = 5;
  2120.         pPrinterPB->writeStatus = noErr;
  2121.         pPrinterPB->writeDrvr.pb = pb;
  2122.         pPrinterPB->writeDrvr.ctl = ctl;
  2123.         if (( pPrinterPB->writePipeRef != NULL ) && (pPrinterPB->printerConfigured))
  2124.         {
  2125.             SetNullUSBParamBlock( pPrinterPB->writePipeRef,  usbprint );
  2126.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, kPStrPrinterDriverName"Set up to do bulk write", pb->ioReqCount );
  2127.             usbprint->usbActCount = 0;
  2128.             usbprint->usbBuffer = pb->ioBuffer;
  2129.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  2130.             usbprint->usbCompletion = (USBCompletion) WriteCompletion;
  2131.             
  2132. #if MAX_USB_TRANSFER_SIZE
  2133.             //
  2134.             //    the completion routine will queue another BulkWrite until we exhaust the data
  2135.             //        or there is an error which can't be retried
  2136.             //
  2137.             if ( pb->ioReqCount > MAX_USB_TRANSFER_SIZE )
  2138.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  2139.             else
  2140. #endif
  2141.                 usbprint->usbReqCount = pb->ioReqCount;
  2142.     
  2143.  
  2144. #if DOUBLE_BUFFER
  2145.             //
  2146.             //    make sure we have enough room in our buffer
  2147.             //    then copy the user data into our page aligned buffer
  2148.             //
  2149.             if ( usbprint->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  2150.                 usbprint->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  2151.             BlockCopy( usbprint->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, usbprint->usbReqCount );
  2152.             usbprint->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  2153. #endif
  2154.             pb->ioResult = ioInProgress;
  2155.     
  2156. #if LOCK_MEMORY
  2157.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  2158.             IF_DEBUG( if ( err != noErr ) DebugStr( kPStrPrinterDriverName"QueueWrite LockMem failed" ) );
  2159.             if ( err == noErr )
  2160. #endif
  2161.                 err = SafeUSBBulkWrite( usbprint );
  2162.             if ( immediateError(err) )
  2163.             {
  2164.                 MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, kPStrPrinterDriverName"Immediate error doing bulk write",0 );
  2165.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  2166.                 usbprint->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  2167.                 pb->ioResult = err;
  2168.             }
  2169.             //
  2170.             //    note our logging is one write for each the client request
  2171.             //        not one write for each usb transaction
  2172.             //
  2173.             LOGGING( fwrite( pb->ioBuffer, sizeof(char), pb->ioReqCount, logfile ) );
  2174.         }
  2175.         else
  2176.         {
  2177.             MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, kPStrPrinterDriverName"Write to unopened pipe" , usbprint->usbStatus );
  2178.             pb->ioResult = abortErr;
  2179.         }
  2180.     }
  2181. }
  2182.  
  2183.  
  2184. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2185.     Name:        Abort
  2186.  
  2187.     Input Parameters:    
  2188.         refNum            DRVR refnum
  2189.         pPrinterPB        current printing device class's storage
  2190.  
  2191.     Output Parameters:
  2192.         
  2193.     Description:
  2194.         Asynchronous completion.
  2195.         Note: USBAbortPipeByReference can leave the data toggle in the wrong state.
  2196.                 We need to abort both pipes, and then the client must soft reset the printer
  2197.                 to get the printer's data toggles correct.
  2198.         We prematurely call completion routines for active i/o so that CloseDriverSync
  2199.             will not hang the system after an abort, including hot unplug. This works out okay,
  2200.             since the request will be dequeued now, and when the i/o actually terminates
  2201.             the system will be called with an invalid queue element and then reject this second
  2202.             attempt to dequeue the i/o.
  2203.  
  2204.  
  2205.  
  2206.  
  2207. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2208. OSStatus
  2209. Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
  2210. {
  2211.     OSStatus        err = noErr;
  2212.  
  2213.     //
  2214.     //    if there's any pending io this will call the completion routine
  2215.     //
  2216.     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, "\pUSB Print - Abort called" , 0);
  2217.     if (refNum == pPrinterPB->outRefNum)
  2218.     {
  2219.         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, "\pUSB Print - Abort called on out pipe" , 0);
  2220.         if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
  2221.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName "***** Abort with write in progress" , 0);
  2222.         
  2223.         err = USBResetPipeByReference( pPrinterPB->writePipeRef );    // Do this instead of Abort/Clear, this works
  2224.         
  2225.         if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
  2226.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->writeDrvr.pb, pPrinterPB->writeDrvr.ctl ); 
  2227.     }
  2228.     
  2229.     if (refNum == pPrinterPB->inRefNum)
  2230.     {
  2231.         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, "\pUSB Print - Abort called on in pipe" , 0);
  2232.         if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
  2233.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName "***** Abort with read in progress" , 0);
  2234.  
  2235.         err = USBResetPipeByReference( pPrinterPB->readPipeRef );    // Do this instead of Abort/Clear, this works
  2236.  
  2237.         if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
  2238.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->readDrvr.pb, pPrinterPB->readDrvr.ctl ); 
  2239.     }
  2240.     return err;
  2241. }
  2242.  
  2243.  
  2244. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2245.     Name:        CompletionProc
  2246.  
  2247.     Input Parameters:    
  2248.         pb                    USB param block ptr
  2249.     
  2250.     Output Parameters:
  2251.         
  2252.     Description:
  2253.         Asynchronous completion routine for DRVR requests.
  2254.  
  2255.  
  2256.  
  2257.  
  2258.  
  2259. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2260. static void 
  2261. CompletionProc(USBPB *pb)
  2262. {
  2263.     //    call the user completion routine
  2264.     struct usbPrinterPBStruct
  2265.                     *pPrinterPB = (struct usbPrinterPBStruct    *) pb->usbRefcon;
  2266.     IOParamPtr     clientParam = pPrinterPB->statusDrvr.pb;
  2267.  
  2268.     clientParam->ioActCount = pb->usbActCount;
  2269.  
  2270.     if ( pb->usbStatus != noErr ) 
  2271.     {
  2272.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  2273.  
  2274.         IF_DEBUG( MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName "CompletionProc Error" , pb->usbStatus ) );
  2275.         IF_DEBUG( MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  2276.     }
  2277.  
  2278.     pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  2279.     if ( pPrinterPB->statusDrvr.ctl != NULL )
  2280.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl ); 
  2281. }
  2282.  
  2283. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2284.     Name:        CentronicsStatus
  2285.  
  2286.     Input Parameters:    
  2287.         pb                        MacOS device manager parameter block
  2288.         ctl                    device manager dCtl block
  2289.         pPrinterPB            current printing device class's storage
  2290.  
  2291.     Output Parameters:
  2292.         pStatusByte        
  2293.         
  2294.     Description:
  2295.         setup the device request for a USB printer class request one byte status.
  2296.  
  2297.  
  2298.  
  2299.  
  2300.  
  2301. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2302. static void
  2303. CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
  2304. {
  2305.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2306.  
  2307.     usbprint->usb.cntl.BRequest = kUSBPrintClassGetCentronicsStatus;
  2308.     usbprint->usb.cntl.WValue = 0;
  2309.     usbprint->usb.cntl.WIndex = interfaceNumber;
  2310.  
  2311.     usbprint->usbReqCount = 1;
  2312.     usbprint->usbBuffer = buffer;
  2313. }
  2314.  
  2315. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2316.     Name:        ClearEndpointHalt
  2317.  
  2318.     Input Parameters:    
  2319.         usbprint                USB param block
  2320.  
  2321.     Output Parameters:
  2322.         
  2323.     Description:
  2324.         Setup the device request for a USB clear endpoint halt.
  2325.  
  2326. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2327. void
  2328. ClearEndpointHalt( USBPB *usbprint)
  2329. {
  2330.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBEndpoint);
  2331.  
  2332.     usbprint->usb.cntl.BRequest = kUSBRqClearFeature;
  2333.     usbprint->usb.cntl.WValue = kUSBFeatureEndpointStall;
  2334.     usbprint->usbFlags = kUSBAddressRequest;
  2335.  
  2336.     usbprint->usbReqCount = 0;
  2337.     usbprint->usbBuffer = NULL;
  2338.     
  2339.  
  2340. }
  2341.  
  2342. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2343.     Name:        SoftReset
  2344.  
  2345.     Input Parameters:    
  2346.         usbprint                USB param block
  2347.         interfaceNumber
  2348.  
  2349.     Output Parameters:
  2350.         
  2351.     Description:
  2352.         Setup the device request for a USB printer class request soft reset.
  2353.  
  2354.  
  2355.  
  2356.  
  2357.  
  2358. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2359. void
  2360. SoftReset( USBPB *usbprint, short interfaceNumber )
  2361. {
  2362.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
  2363.  
  2364.     usbprint->usb.cntl.BRequest = kUSBPrintClassSoftReset;
  2365.     usbprint->usb.cntl.WValue = 0;
  2366.     usbprint->usb.cntl.WIndex = interfaceNumber;
  2367.  
  2368.     usbprint->usbReqCount = 0;
  2369.     usbprint->usbBuffer = NULL;
  2370.     
  2371.  
  2372. }
  2373.  
  2374. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2375.     Name:        CapabilityRequest
  2376.  
  2377.     Input Parameters:    
  2378.         usbprint            USB parameter block
  2379.         p                    result pointer
  2380.         length            amount of data allocated
  2381.         config
  2382.         interfaceNum
  2383.         alternateSetting
  2384.         
  2385.  
  2386.     Output Parameters:
  2387.         p                    result pointer
  2388.         length            amount of data allocated
  2389.         
  2390.     Description:
  2391.         setup the device request for a USB printer class request 1284 id string.
  2392.  
  2393.  
  2394.  
  2395.  
  2396.  
  2397. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2398. void
  2399. CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting  )
  2400. {
  2401.  
  2402.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2403.  
  2404.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  2405.     pb->usb.cntl.WValue = configValue;        // configuration
  2406.     pb->usb.cntl.WIndex = (interfaceNumber<<8) | alternateSetting;
  2407.  
  2408.     pb->usbReqCount = length;
  2409.     pb->usbBuffer = p;
  2410.  
  2411. }
  2412.  
  2413. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2414.     Name:        StatusControlRequests
  2415.  
  2416.     Input Parameters:    
  2417.         pb                        MacOS device manager parameter block
  2418.         ctl                    device manager dCtl block
  2419.         pPrinterPB            current printing device class's storage
  2420.  
  2421.     Output Parameters:
  2422.         
  2423.     Description:
  2424.         Asynchronous completion.
  2425.  
  2426.  
  2427.  
  2428.  
  2429. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2430.  
  2431. void
  2432. ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  2433. {
  2434.  
  2435.     //
  2436.     //    queue a transaction to retrieve the centronics status
  2437.     //
  2438.     OSStatus    err;
  2439.     USBPB        *usbprint = &pPrinterPB->pb;
  2440.     Boolean        dosomething = false;
  2441.     
  2442. #if DEBUG
  2443.     Str255        text;
  2444.  
  2445.     sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
  2446.     text[0] = CStrLen((char *)text); // c2pstr
  2447.     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, text, usbprint->usbStatus );
  2448. #endif
  2449.  
  2450.  
  2451.  
  2452.     if (pPrinterPB->terminating)
  2453.     {
  2454.         pb->ioResult = abortErr;
  2455.     }
  2456.     else
  2457.     {
  2458.         switch( ((CntrlParam *) pb)->csCode )
  2459.         {
  2460.         case kDrvrCentronicsStatus:
  2461.             dosomething = true;
  2462.             CentronicsStatus( usbprint,  *((Ptr *)((CntrlParam *) pb)->csParam), pPrinterPB->interfaceNumber );
  2463.             SetNullUSBParamBlock(pPrinterPB->deviceRef,  usbprint );
  2464.             break;
  2465.             
  2466.             
  2467.         case kDrvr1284IdString:
  2468.             dosomething = true;
  2469.             CapabilityRequest( usbprint,
  2470.                                     *((Ptr *)((CntrlParam *) pb)->csParam),
  2471.                                     *((long *) &((CntrlParam *) pb)->csParam[4]),
  2472.                                     0,        // configuration
  2473.                                     pPrinterPB->interfaceNumber,
  2474.                                     pPrinterPB->alternateSetting);
  2475.             SetNullUSBParamBlock(pPrinterPB->deviceRef,  usbprint );
  2476.             break;
  2477.             
  2478.         case kDrvrSoftReset:
  2479.             dosomething = true;
  2480.             if ( ((CntrlParam *) pb)->ioCRefNum == pPrinterPB->outRefNum )
  2481.             {
  2482.                 SetNullUSBParamBlock(pPrinterPB->writePipeRef,  usbprint );
  2483.             }
  2484.             else 
  2485.             {
  2486.                 SetNullUSBParamBlock(pPrinterPB->readPipeRef,  usbprint );
  2487.             }
  2488.             ClearEndpointHalt( usbprint );
  2489.             break;
  2490.         
  2491.         case kDrvrPrivateLog:
  2492.             // BT - 15Jun99, print a message in the log for the 68k code.
  2493.             MyUSBExpertStatusLevel(((CntrlParam *) pb)->csParam[2], pPrinterPB->deviceRef, *(unsigned char **)(((CntrlParam *) pb)->csParam), *((long *)&((CntrlParam *) pb)->csParam[4]) );
  2494.             return;
  2495.             break;
  2496.         
  2497.         case kDrvrPrivateOpnClose:
  2498.             if (gUSBVersion >= kUSBv135)
  2499.             {
  2500.                 // BT - 15Jun99, Open or close has been called, arrange for suspend or resume.
  2501.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, "\pUSB print driver kDrvrPrivateOpnClose", ((CntrlParam *) pb)->csParam[0] == 0);
  2502.                 // If csParam[0] is 1 we're being opened, if 0 we're being closed
  2503.                 if(((CntrlParam *) pb)->csParam[0] == 1)
  2504.                 {
  2505.                     openRef++;
  2506.                     wantToBe = kUSBPrintResumed;
  2507.                     // We're being opened
  2508.                 }
  2509.                 else if(((CntrlParam *) pb)->csParam[0] == 0)
  2510.                 {
  2511.                     if (--openRef < 0) 
  2512.                         openRef = 0;
  2513.                     
  2514.                     if (!openRef)  // is this the last close?
  2515.                         wantToBe = kUSBPrintSuspended;
  2516.                     else
  2517.                         wantToBe = kUSBPrintResumed;
  2518.                 }
  2519.                 else
  2520.                 {
  2521.                     MyUSBExpertStatusLevel(2, pPrinterPB->deviceRef, "\pUSB print driver kDrvrPrivateOpnClose unknown message", ((CntrlParam *) pb)->csParam[0] == 0);
  2522.                 }
  2523.                 USBPrintDoSuspendResume(pPrinterPB->interfaceRef);
  2524.             }
  2525.             return;
  2526.             break;
  2527.         default:
  2528.             break;
  2529.         }
  2530.     
  2531.         if ( !dosomething )
  2532.             pb->ioResult = paramErr;
  2533.         else
  2534.         {
  2535.             // BT - 15Jun99, if we're not currently awake, delay this until we are.
  2536.             if(currentlyAre == kUSBPrintSuspended )
  2537.             {
  2538.                 
  2539.                 if (Cpb != nil){
  2540.                     pb->ioResult = notOpenErr;
  2541.                     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, Can't support more than one delayed control call while suspended!", pb->ioResult );
  2542.                     return;
  2543.                 }
  2544.                     
  2545.                 pb->ioResult = ioInProgress;
  2546.                 MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, delaying control for resume", 0 );
  2547.                 CpPrinterPB = pPrinterPB;
  2548.                 Cctl = ctl;
  2549.                 Cpb = pb;
  2550.                 if( (currentlyAre != kUSBPrintSuspended) && (Rpb != nil) )
  2551.                 {
  2552.                     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, resumed while we wern't looking", 0 );
  2553.                     // resumed and executed this while we were doing this.
  2554.                     return;
  2555.                 }
  2556.                 else
  2557.                 {
  2558.                     // now wait for resume to happen
  2559.                     MyUSBExpertStatusLevel(kDebugStatusLevel, usbprint->usbReference, "\pUSB Print, let resume take over", 0 );
  2560.                     return;
  2561.                 }        
  2562.             }
  2563.  
  2564.             usbprint->usbActCount = 0;
  2565.             usbprint->usbCompletion = (USBCompletion)CompletionProc;
  2566.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  2567.         
  2568.             pb->ioResult = ioInProgress;
  2569.             pPrinterPB->statusDrvr.pb = pb;
  2570.             pPrinterPB->statusDrvr.ctl = ctl;
  2571.         
  2572.             err = USBDeviceRequest(usbprint);
  2573.             if(immediateError(err))
  2574.             {
  2575.                 USBExpertFatalError(usbprint->usbReference, err, kPStrPrinterDriverName"StatusControlRequests", 0);
  2576.                 usbprint->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  2577.                 pb->ioResult = err;
  2578.             }
  2579.         }
  2580.     }
  2581. }
  2582.  
  2583.  
  2584. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2585.     Name:        PrinterDeviceCompletionProc
  2586.  
  2587.     Input Parameters:    
  2588.         pb                refCon tells which state we're completing
  2589.  
  2590.     Output Parameters:
  2591.         <none>
  2592.         
  2593.     Description:
  2594.         Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
  2595.  
  2596.  
  2597.  
  2598.  
  2599.  
  2600.  
  2601.  
  2602.  
  2603.  
  2604.  
  2605. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2606.  
  2607. static void 
  2608. PrinterDeviceCompletionProc(USBPB *pb)
  2609. {
  2610. Str255        tempstr1,tempstr2;
  2611. register     struct usbPrinterPBStruct *pPrinterPB;
  2612. OSStatus    err;
  2613. UInt32        i = 0;
  2614.     
  2615.     
  2616.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2617.  
  2618.     pPrinterPB->transDepth--; 
  2619.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2620.     {
  2621.         USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, kPStrPrinterDriverName "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
  2622.     }
  2623.  
  2624.     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString) , pPrinterPB->pb.usbStatus );
  2625.  
  2626.     pPrinterPB->delayInProgress = false;
  2627.     
  2628.     if ( pPrinterPB->terminating )
  2629.     {
  2630.         //    if we've been hot unplugged
  2631.         //        don't startup any new transactions
  2632.         //     allow PrintDriverFinalize to continue
  2633.         pPrinterPB->pb.usbStatus = kUSBAbortedError;
  2634.         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2635.     }
  2636.     
  2637.  
  2638.     switch( pPrinterPB->pb.usbStatus )
  2639.     {
  2640.         case kUSBPending:
  2641.         case noErr:
  2642.             pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
  2643.             pPrinterPB->retryCount = kPrinterRetryCount;
  2644.             break;
  2645.             
  2646.         case kUSBLinkErr:
  2647.         case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  2648.         case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  2649.         case kUSBDataToggleErr:                            /*  Pipe stall, Bad data toggle */
  2650.         case kUSBNotRespondingErr:                        /*  Pipe stall, No device, device hung */
  2651.         case kUSBPIDCheckErr:                            /*  Pipe stall, PID CRC error */
  2652.         case kUSBWrongPIDErr:                            /*  Pipe stall, Bad or wrong PID */
  2653.         case kUSBTimedOut:                                /* Transaction timed out. */
  2654.         default:
  2655.         
  2656.             USBClearPipeStallByReference(pPrinterPB->deviceRef);  // we got an error, try to clear any stalls
  2657.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName "    retry", pPrinterPB->pb.usbStatus);
  2658.             
  2659.             // clear out the transaction pending flag
  2660.             pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2661.             pPrinterPB->pb.usbRefcon |= kRetryTransaction;
  2662.             pPrinterPB->retryCount--;
  2663.             if (!pPrinterPB->retryCount)
  2664.             {
  2665.                 USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, kPStrPrinterDriverName "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
  2666.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2667.             } 
  2668.             else 
  2669.             {
  2670.                 pPrinterPB->pb.usbStatus = noErr;             // let's retry one more time
  2671.             }
  2672.             break;
  2673.             
  2674.         case kUSBNotFound:
  2675.             break;
  2676.             
  2677.         case kUSBAbortedError:                        /* user cancel, or hot unplug */
  2678.             // clear out the transaction pending flag
  2679.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2680.             pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2681.             pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2682.             break;
  2683.     }
  2684.  
  2685.     if (pPrinterPB->pb.usbRefcon & kTransactionPending)             
  2686.     {            
  2687.         short    length;
  2688.     
  2689.         //
  2690.         //    advance to the next state
  2691.         //
  2692.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kReturnFromDriver);
  2693.         switch(pPrinterPB->pb.usbRefcon)
  2694.         {
  2695.             case kFindInterface_bidirectional:
  2696.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kFindInterface_bidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
  2697.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2698.                 {
  2699.                     if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) && 
  2700.                         (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
  2701.                         (pPrinterPB->pb.usbProtocol == kUSBPrinterBidirectionalProtocol))
  2702.                     {
  2703.                         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Found bidirectional interface at alt setting ", pPrinterPB->pb.usbOther);
  2704.                         pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
  2705.                         pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
  2706.                         pPrinterPB->printerProtocol = kUSBPrinterBidirectionalProtocol;
  2707.                         
  2708.                         // if we started out as a device class driver, then the interface descriptor will be NULL
  2709.                         // this would mean that the device will need to be opened before anything can be done with it
  2710.                         // if the interface descriptor point isn't null, then we started as an interface driver,
  2711.                         // so just skip by the opendevice call
  2712.                         if (pPrinterPB->pInterfaceDescriptor != NULL)
  2713.                         {
  2714.                         // did we find the interface we were looking for?
  2715.                             if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
  2716.                             {
  2717.                                 pPrinterPB->pb.usbRefcon = kSetInterface;
  2718.                             }
  2719.                             else
  2720.                             {
  2721.                                 USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kFindInterface_Bidirectional didn't find the right interface", 0);
  2722.                             }
  2723.                         }
  2724.                         else
  2725.                         {
  2726.                             pPrinterPB->pb.usbRefcon = kOpenDevice;
  2727.                             pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
  2728.                         }
  2729.                     }
  2730.                 }
  2731.                 else
  2732.                 {
  2733.                     if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
  2734.                     {
  2735.                         MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Bidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
  2736.                         pPrinterPB->pb.usbRefcon = kFindInterface_unidirectional;
  2737.                         pPrinterPB->pb.usbStatus = noErr;  // must clear error for state machine to continue <USB46>
  2738.                     }
  2739.                     else
  2740.                     {
  2741.                         USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kFindInterface_bidirectional failed", 0);
  2742.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2743.                     }
  2744.                 }
  2745.                 break;
  2746.                 
  2747.             case kFindInterface_unidirectional:
  2748.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kFindInterface_unidirectional completed", pPrinterPB->pb.usb.cntl.WIndex);
  2749.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2750.                 {
  2751.                     if ((pPrinterPB->pb.usbClassType == kUSBPrintingClass) && 
  2752.                         (pPrinterPB->pb.usbSubclass == kUSBPrinterSubclass) &&
  2753.                         (pPrinterPB->pb.usbProtocol == kUSBPrinterUnidirectionalProtocol))
  2754.                     {
  2755.                         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Found unidirection interface at alt setting ", pPrinterPB->pb.usbOther);
  2756.                         pPrinterPB->pb.usbRefcon = kOpenDevice;
  2757.                         pPrinterPB->configurationNumber = pPrinterPB->pb.usb.cntl.WValue;
  2758.                         pPrinterPB->alternateSetting = pPrinterPB->pb.usbOther;
  2759.                         pPrinterPB->printerProtocol = kUSBPrinterUnidirectionalProtocol;
  2760.                         // if we started out as a device class driver, then the interface descriptor will be NULL
  2761.                         // this would mean that the device will need to be opened before anything can be done with it
  2762.                         // if the interface descriptor point isn't null, then we started as an interface driver,
  2763.                         // so just skip by the opendevice call
  2764.                         if (pPrinterPB->pInterfaceDescriptor)
  2765.                         {
  2766.                             if (pPrinterPB->interfaceNumber == pPrinterPB->pb.usb.cntl.WIndex)
  2767.                             {
  2768.                                 pPrinterPB->pb.usbRefcon = kSetInterface;
  2769.                             }
  2770.                             else
  2771.                             {
  2772.                                 USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kFindInterface_Unidirectional didn't find the right interface", 0);
  2773.                             }
  2774.                         }
  2775.                         else
  2776.                         {
  2777.                             pPrinterPB->pb.usbRefcon = kOpenDevice;
  2778.                             pPrinterPB->interfaceNumber = pPrinterPB->pb.usb.cntl.WIndex;
  2779.                         }
  2780.                     }
  2781.                 }
  2782.                 else
  2783.                 {
  2784.                     if ( pPrinterPB->pb.usbStatus == kUSBNotFound )
  2785.                     {
  2786.                         MyUSBExpertStatusLevel(kNormalStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"Unidirectional interface was not found", pPrinterPB->pb.usb.cntl.WIndex);
  2787.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2788.                     }
  2789.                     else
  2790.                     {
  2791.                         USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kFindInterface_unidirectional failed", 0);
  2792.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2793.                     }
  2794.                 }
  2795.                 break;
  2796.                 
  2797.             case kOpenDevice:
  2798.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2799.                 {
  2800.                     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kOpenDevice completed", pPrinterPB->pb.usbStatus);
  2801.                     pPrinterPB->pb.usbRefcon = kNewInterfaceRef;
  2802.                 }
  2803.                 else
  2804.                 {
  2805.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kOpenDevice failed", 0);
  2806.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2807.                 }
  2808.                 break;
  2809.                 
  2810.             case kNewInterfaceRef:
  2811.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kNewInterfaceRef completed", pPrinterPB->pb.usbReference);
  2812.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2813.                 {
  2814.                     pPrinterPB->interfaceRef = pPrinterPB->pb.usbReference;
  2815.                     pPrinterPB->pb.usbRefcon = kSetInterface;
  2816.                 }
  2817.                 else
  2818.                 {
  2819.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kNewInterfaceRef failed", 0);
  2820.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2821.                 }
  2822.                 break;
  2823.             
  2824.             case kSetInterface:
  2825.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kSetInterface completed", 0);
  2826.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2827.                 {
  2828.                     pPrinterPB->pb.usbRefcon = kConfigureInterface;
  2829.                 }
  2830.                 else
  2831.                 {
  2832.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kSetInterface failed", 0);
  2833.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2834.                 }
  2835.                 break;
  2836.             
  2837.             case kConfigureInterface:
  2838.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kConfigureInterface completed, pipes = ", pPrinterPB->pb.usbOther);
  2839.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2840.                 {
  2841.                     pPrinterPB->pipeCount = pPrinterPB->pb.usbOther;
  2842.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2843.                 }
  2844.                 else
  2845.                 {
  2846.                     USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kConfigureInterface failed", 0);
  2847.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2848.                 }
  2849.                 break;
  2850.             
  2851.             case kGetCapabilityString:
  2852.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kGetCapabilityString completed", pPrinterPB->pb.usbStatus);
  2853.                 
  2854.                 if ( pPrinterPB->pb.usbActCount >= 2 )
  2855.                 {
  2856.                     length = pPrinterPB->pCapabilityString[1] | (pPrinterPB->pCapabilityString[0] << 8);
  2857.                 }
  2858.                 else
  2859.                 {
  2860.                     length = 0;
  2861.                 }
  2862.     
  2863.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2864.                 {
  2865.                     //
  2866.                     //    In the short term (fall '98) several vendors are planning on shipping 
  2867.                     //        devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
  2868.                     //    Unfortunately this isn't an ideal solution from the USB perspective:
  2869.                     //        users can leave the printer off while the cable responds that there's
  2870.                     //        a printer connected. Then we have no way of using the DEVICE_ID
  2871.                     //        string to tag the printer and register it.
  2872.                     //    To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
  2873.                     //        string is null. Every few seconds we'll retry this state.
  2874.                     //    At some point the user wants to print and switches on the printer. The class
  2875.                     //    driver then picks up from here and registers the device properly.
  2876.                     //
  2877.                     
  2878.                     if ( pPrinterPB->pb.usbActCount == 0 )
  2879.                         pPrinterPB->pb.usbRefcon = kDelayGetCapability;
  2880.                     else
  2881.                         pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
  2882.                 }
  2883.                 else
  2884.                 {
  2885.                     if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
  2886.                     {
  2887.                         //
  2888.                         //    if we've haven't managed to read the whole capability string
  2889.                         //        we need to allocate memory and read it in by initiating kGetFullCapabilityString
  2890.                         //
  2891.     
  2892.                         if ( length > sizeof(pPrinterPB->capability) && pPrinterPB->pb.usbRefcon == kGetCapabilityString )
  2893.                         {
  2894.                             pPrinterPB->pb.usbRefcon = kAllocateCapabilityMem;
  2895.                             pPrinterPB->pb.usbStatus = noErr;  // must clear error for state machine to continue <USB46>
  2896.                             break;                               // advance to that state <USB46>
  2897.                         }    
  2898.                         
  2899.                 
  2900.                     }
  2901.                     else
  2902.                     {
  2903.                         USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kGetCapabilityString failed", 0);
  2904.                         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2905.                     }
  2906.                 }
  2907.                 
  2908.                 // write the capability string to the log
  2909.                 if ((pPrinterPB->pb.usbStatus == kUSBOverRunErr)  || (pPrinterPB->pb.usbStatus == noErr))
  2910.                 {
  2911.                     if (length > 2)                     // is there a valid string? (length more than 2 bytes)
  2912.                     {
  2913.                         length -= 2;
  2914.                         if (length > 200)                // cut the string off at 200 characters
  2915.                             length = 200;
  2916.                             
  2917.                         BlockMoveData( (Ptr)&(pPrinterPB->pCapabilityString[2]), (Ptr)tempstr2, length);
  2918.                         tempstr2[length] = '\0';        // mark the end of the cstring
  2919.                         
  2920.                         sprintf( (char *)tempstr1, (char const *) kCStrPrinterDriverName"1284 Capability String: %s", tempstr2 );
  2921.                         CStrToPStr( (unsigned char *)tempstr2, (char *)tempstr1);    // convert it to a pstring
  2922.                     }
  2923.                     else
  2924.                     {
  2925.                         CStrToPStr( (unsigned char *)tempstr2, (char *) kCStrPrinterDriverName"Capability string is empty!!" );
  2926.                     }
  2927.                     MyUSBExpertStatusLevel(kNormalStatusLevel,  pPrinterPB->deviceRef, tempstr2, length);
  2928.                 }
  2929.                 break;
  2930.                 
  2931.             case kDelayGetCapability:
  2932.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kDelayGetCapability completed", pPrinterPB->pb.usbStatus);
  2933.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2934.                 {
  2935.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2936.                 }
  2937.                 else
  2938.                 {
  2939.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kDelayGetCapability failed", 0);
  2940.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2941.                 }
  2942.                 break;
  2943.                 
  2944.             case kAllocateCapabilityMem:
  2945.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kAllocateCapabilityMem completed", pPrinterPB->pb.usbStatus);
  2946.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2947.                 {
  2948.                     pPrinterPB->pCapabilityString = pPrinterPB->pb.usbBuffer;
  2949.                     pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;    
  2950.                 }
  2951.                 else
  2952.                 {
  2953.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kAllocateCapabilityMem failed", 0);
  2954.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2955.                 }
  2956.                 break;
  2957.             
  2958.             case kGetFullCapabilityString:
  2959.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kGetFullCapabilityString completed", pPrinterPB->pb.usbStatus);
  2960.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2961.                 {
  2962.                     pPrinterPB->pb.usbRefcon = kGetInterface;
  2963.                 }
  2964.                 else
  2965.                 {
  2966.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kGetFullCapabilityString failed", 0);
  2967.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2968.                 }
  2969.                 break;
  2970.                 
  2971.             case kGetInterface:
  2972.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kGetInterface completed", pPrinterPB->pb.usbStatus);
  2973.                 if (( pPrinterPB->pb.usbStatus == noErr ) && (pPrinterPB->whichAltInterface == pPrinterPB->alternateSetting))
  2974.                 {
  2975.                     pPrinterPB->pb.usbRefcon = kFindBulkOutPipe;
  2976.                 }
  2977.                 else
  2978.                 {
  2979.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kGetInterface - wrong interface selected", pPrinterPB->whichAltInterface);
  2980.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  2981.                 }
  2982.                 break;
  2983.  
  2984.             case kFindBulkOutPipe:
  2985.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kFindBulkOutPipe completed", pPrinterPB->pb.usbReference);
  2986.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2987.                 {
  2988.                     pPrinterPB->writePipeRef = pPrinterPB->pb.usbReference;             // remember the ref
  2989.                     pPrinterPB->out = pPrinterPB->pb;                                    // copy the paramblock
  2990.                     pPrinterPB->out.usbCompletion =  (USBCompletion) NULL;                // for finalize
  2991.  
  2992.                     if ( pPrinterPB->printerProtocol == kUSBPrinterBidirectionalProtocol )
  2993.                         pPrinterPB->pb.usbRefcon = kFindBulkInPipe;
  2994.                     else
  2995.                         pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
  2996.                 }
  2997.                 else
  2998.                 {
  2999.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kFindBulkOutPipe failed", 0);
  3000.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3001.                 }
  3002.                 break;
  3003.                 
  3004.             case kFindBulkInPipe:
  3005.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kFindBulkInPipe completed", pPrinterPB->pb.usbReference);
  3006.                 if ( pPrinterPB->pb.usbStatus == noErr )
  3007.                 {
  3008.                     pPrinterPB->readPipeRef = pPrinterPB->pb.usbReference;
  3009.                     pPrinterPB->in = pPrinterPB->pb;                                    // copy the paramblock
  3010.                     pPrinterPB->in.usbCompletion =  (USBCompletion) NULL;                // for finalize
  3011.  
  3012.                     pPrinterPB->pb.usbRefcon = kTaskTimeRequired;
  3013.                 }
  3014.                 else
  3015.                 {
  3016.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"kFindBulkInPipe failed", 0);
  3017.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3018.                 }
  3019.                 break;
  3020.                 
  3021.             case kTaskTimeRequired:
  3022.                 MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kTaskTimeRequired completed (now at task time)", pPrinterPB->pb.usbReference);
  3023.             //
  3024.             //    once we know what device we're dealing with
  3025.             //        open the i/o channel(s) to the device
  3026.             //        and enter it in the name registry
  3027.             //
  3028.                 
  3029.                 err = InstallDrivers( pPrinterPB );
  3030.                 if ( err == noErr )
  3031.                 {
  3032.                     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kTaskTimeRequired - drivers installed", pPrinterPB->pb.usbReference);
  3033.                     err = RegisterDevice( pPrinterPB );
  3034.                     if ( err == noErr )
  3035.                     {
  3036.                         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kTaskTimeRequired - RegisterDevice successful", pPrinterPB->pb.usbReference);
  3037.                     }
  3038.                     else
  3039.                     {
  3040.                         USBExpertFatalError(pPrinterPB->interfaceRef, err, kPStrPrinterDriverName"kTaskTimeRequired - RegisterDevice failed", 0);
  3041.                     }
  3042.                 }
  3043.                 else
  3044.                 {
  3045.                     USBExpertFatalError(pPrinterPB->interfaceRef, err, kPStrPrinterDriverName"kTaskTimeRequired - InstallDrivers failed", 0);
  3046.                 }
  3047.     
  3048.                 pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;                    // Finalize
  3049.                 if ( pPrinterPB->pb.usbStatus == noErr )
  3050.                 {
  3051.                     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, "\pPrinter driver now exiting setup, calling suspend", pPrinterPB->interfaceRef );
  3052.                     USBPrintDoSuspendResume(pPrinterPB->interfaceRef); 
  3053.                     pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  3054.                     pPrinterPB->printerConfigured = true;
  3055.                 }
  3056.                 else
  3057.                 {
  3058.                     USBExpertFatalError(pPrinterPB->interfaceRef, pPrinterPB->pb.usbStatus, kPStrPrinterDriverName"RegisterDevice failed", 0);
  3059.                     pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3060.                 }
  3061.                 break;
  3062.                 
  3063.             case kGetCentronicsStatus:
  3064.                 //
  3065.                 //    if InitiateTransaction fell through on it's kTaskTimeRequired case we'll end up here
  3066.                 //
  3067.                 if ( pPrinterPB->pb.usbStatus == noErr )
  3068.                 {
  3069.                     unsigned char text[255];
  3070.                     sprintf( (char *)text, " Centronics Status: 0x%02x", pPrinterPB->centronics.b );
  3071.                     text[0] = CStrLen((char *)text); // c2pstr
  3072.                     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, text, pb->usbStatus );
  3073.                     
  3074. #if DEBUG
  3075.                     if ( !pPrinterPB->centronics.status.notError )
  3076.                     {
  3077.                         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"Error at printer", pPrinterPB->pb.usbStatus);
  3078.                     }
  3079.                     if ( pPrinterPB->centronics.status.paperError )
  3080.                     {
  3081.                         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"Check paper", pPrinterPB->pb.usbStatus);
  3082.                     }
  3083.                     if ( !pPrinterPB->centronics.status.select )
  3084.                     {
  3085.                         MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"printer offline", pPrinterPB->pb.usbStatus);
  3086.                     }
  3087. #endif
  3088.                     pPrinterPB->pb.usbRefcon = kDelayGetCentronicsStatus;
  3089.                 }
  3090.                 else
  3091.                 {
  3092.                     MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kGetCentronicsStatus - error getting centronics status", pPrinterPB->pb.usbStatus);
  3093.                 }
  3094.                 break;
  3095.                 
  3096.             case kDelayGetCentronicsStatus:
  3097.                 //
  3098.                 //    loop around continually getting status
  3099.                 //
  3100.                 if ( pPrinterPB->pb.usbStatus == noErr )
  3101.                 {
  3102.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  3103.                 }
  3104.                 break;
  3105.             case kNilCompletion:
  3106.             default:
  3107.                 if ( pPrinterPB->pb.usbStatus == noErr )
  3108.                     pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  3109.                 break;
  3110.         }
  3111.     }
  3112.     
  3113.     // did the removal notification get called?  If so, don't start another transaction.  Just exit
  3114.    if (!pPrinterPB->terminating)
  3115.     {
  3116.         if (pPrinterPB->pb.usbStatus == noErr )
  3117.         {
  3118.             if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
  3119.                 PrinterDeviceInitiateTransaction(pb);
  3120.         }
  3121.         else if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  3122.         {
  3123.             USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
  3124.             USBExpertFatalError(pPrinterPB->deviceRef, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
  3125.         }
  3126.     }
  3127.     else
  3128.     {
  3129.         pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3130.     }
  3131.     
  3132.     // If we're exiting the driver, then make certain the completion routine is set to NULL
  3133.     // this lets the driver removal task know that there's nothing pending.
  3134.     if ( pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  3135.     {
  3136.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  3137.     }
  3138. }
  3139.  
  3140. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3141.     Name:        PrinterDeviceInitiateTransaction
  3142.  
  3143.     Input Parameters:    
  3144.         pb            USB parameter block
  3145.         
  3146.     Output Parameters:
  3147.         
  3148.     Description:
  3149.         Since USB transactions are asynchronous we use the refCon field
  3150.         in the parameter block to implement the following logic via a state machine.
  3151.  
  3152.         Start out by getting the device configuration descriptor
  3153.         If the device has more than one printing interface
  3154.             If a bidirectional interface exists
  3155.                 select it
  3156.             Else
  3157.                 select the (mandatory) unidirectional interface
  3158.         Get the (mandatory) 1284 capability string
  3159.         Open pipes to the BulkOut (and optional BulkIn) endpoints
  3160.         Install read and write drivers in the unit table
  3161.         Using information from the capability string
  3162.             enter the printer in the MacOS name registry.
  3163.         
  3164.  
  3165.  
  3166.  
  3167.  
  3168.  
  3169.  
  3170. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3171. void
  3172. PrinterDeviceInitiateTransaction(USBPB *pb)
  3173. {
  3174. register struct usbPrinterPBStruct    *pPrinterPB;
  3175. UInt16        length;
  3176. OSStatus    err;
  3177.  
  3178.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  3179.     
  3180.     pPrinterPB->transDepth++;
  3181.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  3182.     {
  3183.         USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, kPStrPrinterDriverName"InitiateTransaction illegal transaction depth", 0);
  3184.     }
  3185.     IF_DEBUG( MyUSBExpertStatusLevel(5, pPrinterPB->deviceRef, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );     
  3186.     
  3187.     pPrinterPB->delayInProgress = false;
  3188.     switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
  3189.     {
  3190.         case kFindInterface_bidirectional:
  3191.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kFindInterface_bidirectional", 0);
  3192.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  3193.             
  3194.             pPrinterPB->pb.usbBuffer = 0;
  3195.             pPrinterPB->pb.usbActCount = 0;
  3196.             pPrinterPB->pb.usbReqCount = 0;
  3197.             pPrinterPB->pb.usb.cntl.WIndex = 0;
  3198.             pPrinterPB->pb.usb.cntl.WValue = 0;
  3199.             pPrinterPB->pb.usbClassType = kUSBPrintingClass;
  3200.             pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
  3201.             pPrinterPB->pb.usbProtocol = kUSBPrinterBidirectionalProtocol;
  3202.             
  3203.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3204.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3205.             err = USBFindNextInterface(pb);
  3206.             if(immediateError(err))
  3207.             {
  3208.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, kPStrPrinterDriverName"kFindInterface_bidirectional - immediate error", err);
  3209.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3210.             }
  3211.             break;
  3212.     
  3213.         case kFindInterface_unidirectional:
  3214.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kFindInterface_unidirectional", 0);
  3215.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  3216.             
  3217.             pPrinterPB->pb.usbBuffer = 0;
  3218.             pPrinterPB->pb.usbActCount = 0;
  3219.             pPrinterPB->pb.usbReqCount = 0;
  3220.             pPrinterPB->pb.usb.cntl.WIndex = 0;
  3221.             pPrinterPB->pb.usb.cntl.WValue = 0;
  3222.             pPrinterPB->pb.usbClassType = kUSBPrintingClass;
  3223.             pPrinterPB->pb.usbSubclass = kUSBPrinterSubclass;
  3224.             pPrinterPB->pb.usbProtocol = kUSBPrinterUnidirectionalProtocol;
  3225.             
  3226.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3227.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3228.             err = USBFindNextInterface(pb);
  3229.             if(immediateError(err))
  3230.             {
  3231.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, kPStrPrinterDriverName"kFindInterface_unidirectional - immediate error", err);
  3232.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3233.             }
  3234.             break;
  3235.     
  3236.         case kOpenDevice:
  3237.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kOpenDevice", 0);
  3238.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  3239.             
  3240.             pPrinterPB->pb.usbBuffer = 0;
  3241.             pPrinterPB->pb.usbActCount = 0;
  3242.             pPrinterPB->pb.usbReqCount = 0;
  3243.             pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->configurationNumber;
  3244.             
  3245.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3246.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3247.             err = USBOpenDevice(pb);
  3248.             if(immediateError(err))
  3249.             {
  3250.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, kPStrPrinterDriverName"USBOpenDevice - immediate error", err);
  3251.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3252.             }
  3253.             break;
  3254.             
  3255.         case kNewInterfaceRef:
  3256.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->deviceRef, kPStrPrinterDriverName"kNewInterfaceRef for interface number", pPrinterPB->interfaceNumber);
  3257.             SetNullUSBParamBlock( pPrinterPB->deviceRef, &pPrinterPB->pb );
  3258.             
  3259.             pPrinterPB->pb.usbBuffer = 0;
  3260.             pPrinterPB->pb.usbActCount = 0;
  3261.             pPrinterPB->pb.usbReqCount = 0;
  3262.             pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;
  3263.             
  3264.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3265.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3266.             err = USBNewInterfaceRef(pb);
  3267.             if(immediateError(err))
  3268.             {
  3269.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, kPStrPrinterDriverName"USBNewInterfaceRef - immediate error", err);
  3270.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3271.             }
  3272.             break;
  3273.             
  3274.  
  3275.         case kSetInterface:
  3276.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kSetInterface to alternate setting", pPrinterPB->alternateSetting);
  3277.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3278.             
  3279.             pPrinterPB->pb.usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
  3280.         
  3281.             pPrinterPB->pb.usb.cntl.BRequest = kUSBRqSetInterface;
  3282.             pPrinterPB->pb.usb.cntl.WValue = pPrinterPB->alternateSetting;        // alternate setting
  3283.             pPrinterPB->pb.usb.cntl.WIndex = pPrinterPB->interfaceNumber;        // interface
  3284.         
  3285.             pPrinterPB->pb.usbReqCount = 0;
  3286.             pPrinterPB->pb.usbBuffer = NULL;
  3287.         
  3288.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3289.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3290.             err = USBDeviceRequest(pb);
  3291.             if(immediateError(err))
  3292.             {
  3293.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, kPStrPrinterDriverName"kSetInterface - immediate error", err);
  3294.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3295.             }
  3296.             break;
  3297.  
  3298.  
  3299.         case kConfigureInterface:
  3300.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kConfigureInterface for alternate setting", pPrinterPB->alternateSetting);
  3301.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3302.             
  3303.             pPrinterPB->pb.usbBuffer = 0;
  3304.             pPrinterPB->pb.usbActCount = 0;
  3305.             pPrinterPB->pb.usbReqCount = 0;
  3306.             pPrinterPB->pb.usbOther = pPrinterPB->alternateSetting;
  3307.             
  3308.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3309.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3310.             err = USBConfigureInterface(pb);
  3311.             if(immediateError(err))
  3312.             {
  3313.                 USBExpertFatalError(pPrinterPB->pb.usbReference, kUSBInternalErr, kPStrPrinterDriverName"USBConfigureInterface - immediate error)", err);
  3314.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3315.             }
  3316.             break;
  3317.             
  3318.         case kGetCapabilityString:
  3319.             //
  3320.             //    once the interface (and alternate) is assinged
  3321.             //        we can retreive the 1284 capability string to see what kind of printer
  3322.             //        is attached
  3323.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kGetCapabilityString", 0);
  3324.             pPrinterPB->pCapabilityString = pPrinterPB->capability;
  3325.             
  3326.             GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, sizeof(pPrinterPB->capability) );
  3327.             break;
  3328.             
  3329.         case kDelayGetCapability:
  3330.             //
  3331.             //    USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
  3332.             //        Delay a few seconds and try again.
  3333.             //        Will succeed when the user turns the printer on.
  3334.             //
  3335.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kDelayGetCapability", 0);
  3336.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3337.             
  3338.             pPrinterPB->pb.usbBuffer = 0;
  3339.             pPrinterPB->pb.usbActCount = 0;
  3340.             pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
  3341.             pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
  3342.             
  3343.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3344.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3345.             pPrinterPB->delayInProgress = true;
  3346.             err = USBDelay(&pPrinterPB->pb);
  3347.             if(immediateError(err))
  3348.             {
  3349.                 USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"kDelayGetCapability - immediate error", 0);
  3350.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3351.             }
  3352.             break;
  3353.             
  3354.         case kAllocateCapabilityMem:
  3355.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kAllocateCapabilityMem", 0);
  3356.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3357.             length = *(UInt16*)(pPrinterPB->capability);
  3358.             pPrinterPB->pb.usbBuffer = 0;
  3359.             pPrinterPB->pb.usbActCount = 0;
  3360.             pPrinterPB->pb.usbReqCount = length;
  3361.             pPrinterPB->pb.usbFlags = 0;
  3362.             
  3363.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3364.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3365.             err = USBAllocMem(&pPrinterPB->pb);
  3366.             if(immediateError(err))
  3367.             {
  3368.                 USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"kAllocateCapabilityMem - immediate error", 0);
  3369.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3370.             }
  3371.             break;
  3372.         
  3373.         case kGetFullCapabilityString:
  3374.             //
  3375.             // the capability string was too long to fit in the statically allocated space
  3376.             // need to release this memory when we finalize our driver
  3377.             //
  3378.  
  3379.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kGetFullCapabilityString", 0);
  3380.             length = *(UInt16*)(pPrinterPB->capability);
  3381.             if ( pPrinterPB->pCapabilityString )
  3382.                 GetCapability( pPrinterPB, pPrinterPB->pCapabilityString, length );
  3383.             else
  3384.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, kPStrPrinterDriverName"Can't allocate capability memory", 0);
  3385.             break;
  3386.             
  3387.         case kGetInterface:
  3388.             // failsafe check that we've got the right setup
  3389.             //    it's possible the device didn't respond to our SetInterface
  3390.             GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
  3391.             break;
  3392.  
  3393.         case kFindBulkOutPipe:
  3394.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kFindBulkOutPipe", 0);
  3395.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3396.             
  3397.             pPrinterPB->pb.usbBuffer = 0;
  3398.             pPrinterPB->pb.usbActCount = 0;
  3399.             pPrinterPB->pb.usbReqCount = 0;
  3400.             pPrinterPB->pb.usbFlags = kUSBOut;
  3401.             pPrinterPB->pb.usbClassType = kUSBBulk;
  3402.             
  3403.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3404.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3405.             err = USBFindNextPipe( &pPrinterPB->pb );
  3406.             if (immediateError(err))
  3407.             {
  3408.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, kPStrPrinterDriverName"kFindBulkOutPipe - immediate error", err);
  3409.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3410.             }
  3411.             break;
  3412.             
  3413.         case kFindBulkInPipe:    
  3414.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kFindBulkInPipe", 0);
  3415.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3416.             
  3417.             pPrinterPB->pb.usbBuffer = 0;
  3418.             pPrinterPB->pb.usbActCount = 0;
  3419.             pPrinterPB->pb.usbReqCount = 0;
  3420.             pPrinterPB->pb.usbFlags = kUSBIn;
  3421.             pPrinterPB->pb.usbClassType = kUSBBulk;
  3422.             
  3423.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3424.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3425.             err = USBFindNextPipe( &pPrinterPB->pb );
  3426.             if (immediateError(err))
  3427.             {
  3428.                 USBExpertFatalError(pPrinterPB->interfaceRef, kUSBInternalErr, kPStrPrinterDriverName"kFindBulkInPipe - immediate error", err);
  3429.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3430.             }
  3431.             break;
  3432.             
  3433.         case kTaskTimeRequired:
  3434.             MyUSBExpertStatusLevel(kDebugStatusLevel, pPrinterPB->interfaceRef, kPStrPrinterDriverName"kTaskTimeRequired", 0);
  3435.              // to stress test usb bus, fallthrough to kGetCentronicsStatus 
  3436.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3437.             
  3438.             pPrinterPB->pb.usbBuffer = 0;
  3439.             pPrinterPB->pb.usbActCount = 0;
  3440.             pPrinterPB->pb.usbReqCount = kUSBNoDelay;
  3441.             pPrinterPB->pb.usbFlags = kUSBTaskTimeFlag;
  3442.             
  3443.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3444.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3445.             pPrinterPB->delayInProgress = true;
  3446.             err = USBDelay(&pPrinterPB->pb);
  3447.             if(immediateError(err))
  3448.             {
  3449.                 USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"kTaskTimeRequired - immediate error", 0);
  3450.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3451.             }
  3452.             break;
  3453.  
  3454.         case kGetCentronicsStatus:
  3455.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3456.  
  3457.             CentronicsStatus( &pPrinterPB->pb,  &pPrinterPB->centronics.b, pPrinterPB->interfaceNumber );
  3458.             
  3459.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3460.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3461.             err = USBDeviceRequest(&pPrinterPB->pb);
  3462.             if(immediateError(err))
  3463.             {
  3464.                 USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"kGetCentronicsStatus Immediate error", 0);
  3465.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3466.             }
  3467.             break;
  3468.             
  3469.         case kDelayGetCentronicsStatus:
  3470.             SetNullUSBParamBlock( pPrinterPB->interfaceRef, &pPrinterPB->pb );
  3471.  
  3472.             pPrinterPB->pb.usbBuffer = 0;
  3473.             pPrinterPB->pb.usbActCount = 0;
  3474.             pPrinterPB->pb.usbReqCount = kUSS720StatusMSDelay;
  3475.             
  3476.             pPrinterPB->pb.usbRefcon |= kTransactionPending;
  3477.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  3478.             pPrinterPB->delayInProgress = true;
  3479.             err = USBDelay(&pPrinterPB->pb);
  3480.             if(immediateError(err))
  3481.             {
  3482.                 USBExpertFatalError(pb->usbReference, err, kPStrPrinterDriverName"kDelayGetCentronicsStatus - immediate error", 0);
  3483.                 pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3484.             }
  3485.             break;
  3486.             
  3487.         default:
  3488.             USBExpertFatalError(pPrinterPB->deviceRef, kUSBInternalErr, kPStrPrinterDriverName"InitiateTransaction - unknown state", pPrinterPB->pb.usbRefcon);
  3489.             pPrinterPB->pb.usbRefcon |= kReturnFromDriver;
  3490.             break;
  3491.     }
  3492.     
  3493.     if (pPrinterPB->pb.usbRefcon & kReturnFromDriver)
  3494.     {
  3495.         pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  3496.         pPrinterPB->pb.usbRefcon &= ~kTransactionPending;
  3497.     }
  3498. }
  3499.  
  3500.  
  3501. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3502.     Name:        PrintDriverEntry
  3503.  
  3504.     Input Parameters:    
  3505.         
  3506.     Output Parameters:
  3507.         
  3508.     Description:
  3509.         This is where the system instantiates a USB printing device.
  3510.  
  3511.         We need to install drivers in the MacOS unitTable, and a reference
  3512.         in the name registry.
  3513.         
  3514.         But the information we need to do this is only available after some 
  3515.         USB transactions have completed. So we initiate here a series of asynchronous
  3516.         USB operations to get that information (by calling the first 
  3517.  
  3518.  
  3519.  
  3520.  
  3521.  
  3522. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3523. void 
  3524. PrintDriverEntry(
  3525.     USBDeviceRef                    deviceRef,
  3526.     USBDeviceDescriptorPtr            pDeviceDesc,
  3527.     USBInterfaceDescriptorPtr        pInterfaceDesc,
  3528.     UInt32                            interfaceNumber
  3529.     )
  3530. {
  3531.     static Boolean        beenThereDoneThat = false;
  3532.     OSStatus                err;
  3533.     
  3534.     
  3535.     RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
  3536.     RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
  3537.     RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
  3538.     RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
  3539.     
  3540.     if( !beenThereDoneThat)
  3541.     {
  3542.         printerClassRecord.terminating = false;
  3543.         printerClassRecord.printerRegistered = false;
  3544.         beenThereDoneThat = true;
  3545.         
  3546.         //DebugStr("\pIn Printer Driver Entry");
  3547.         MyUSBExpertStatusLevel(kNormalStatusLevel, deviceRef, kPStrPrinterDriverName"Starting USB Printer Driver", 0);
  3548.         
  3549.         printerClassRecord.deviceDescriptor = *pDeviceDesc;    /* keep a copy of the device descriptor */
  3550.         printerClassRecord.pInterfaceDescriptor = pInterfaceDesc;
  3551.         printerClassRecord.interfaceNumber = interfaceNumber;
  3552.         
  3553.         printerClassRecord.deviceRef = deviceRef;
  3554.         printerClassRecord.interfaceRef = deviceRef;
  3555.         
  3556.         printerClassRecord.transDepth = 0;            /* init Delay Callback Depth */
  3557.     
  3558.         printerClassRecord.inRefNum =  -1;            /* initially no DRVRs added to UnitTable */
  3559.         printerClassRecord.outRefNum =  -1;    
  3560.         err = LoadResources( &printerClassRecord );
  3561.         if ( err != noErr )  
  3562.             USBExpertFatalError( deviceRef, err, kPStrPrinterDriverName"LoadResources failed", 0);
  3563.         //
  3564.         //    routines to write and read to the device must be called by 68K DRVR
  3565.         //        so we use mixed-mode manager to dispatch between PPC and 68K
  3566.         //
  3567.         printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
  3568.         printerClassRecord.qwriteRD = qw;
  3569.     
  3570.         printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
  3571.         printerClassRecord.qreadRD = qr;    
  3572.         
  3573.         printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
  3574.         printerClassRecord.qstatusRD = qs;
  3575.  
  3576.         printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
  3577.         printerClassRecord.qabortRD = qa;
  3578.  
  3579.         printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
  3580.         printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
  3581.         printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
  3582.         printerClassRecord.a = (AbortUPP) Abort;
  3583.    
  3584.         SetNullUSBParamBlock( deviceRef, &printerClassRecord.pb );
  3585.         SetNullUSBParamBlock( 0, &printerClassRecord.in );        // fill in pipe ref later
  3586.         SetNullUSBParamBlock( 0, &printerClassRecord.out );    // fill in pipe ref later
  3587.         
  3588.         CStrCopy((char *)printerClassRecord.name, "");
  3589.         CStrCopy((char *)printerClassRecord.model, "");
  3590.  
  3591. #if DOUBLE_BUFFER
  3592.         //
  3593.         // Assume 1. TRANSFER_SIZE is a power of 2
  3594.         //    Assume 2. malignedBuffer is allocated to be 3*TRANSFER_SIZE
  3595.         //
  3596.         printerClassRecord.pageWriteAlignedBufferSize = TRANSFER_SIZE;                            // should get this from VM
  3597.         printerClassRecord.pageWriteAlignedBuffer = printerClassRecord.malignedBuffer;
  3598.  
  3599.         // align it below the buffer, then bring it into the range of the buffer
  3600.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) &= ~(printerClassRecord.pageWriteAlignedBufferSize - 1);    //assumption1
  3601.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) += printerClassRecord.pageWriteAlignedBufferSize;            //assumption2
  3602.  
  3603.         printerClassRecord.pageReadAlignedBufferSize = TRANSFER_SIZE;
  3604.         printerClassRecord.pageReadAlignedBuffer = printerClassRecord.pageWriteAlignedBuffer + TRANSFER_SIZE;
  3605.         
  3606. #endif
  3607.         printerClassRecord.printerConfigured = false;
  3608.     
  3609.         //
  3610.         //    Just to be thorough, lets hold our paramter blocks so that we won't page them at
  3611.         //        interrupt time. (We should be in the System heap and automatically held.)
  3612.         //
  3613.         HoldMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  3614.  
  3615.         CheckUSBVersion();
  3616.         
  3617.         //
  3618.         // Start out at first state
  3619.         //
  3620.         printerClassRecord.pCapabilityString = printerClassRecord.capability;
  3621.         printerClassRecord.pb.usbRefcon = kFindInterface_bidirectional;
  3622.         
  3623.         // don't start if we received a removal notification just as we're starting up
  3624.         if (printerClassRecord.terminating)
  3625.         {
  3626.             printerClassRecord.pb.usbCompletion    = (USBCompletion) NULL;
  3627.         }
  3628.         else
  3629.         {
  3630.             PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
  3631.         }
  3632.     }
  3633. }
  3634.  
  3635. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3636.     Name:        PrinterRemovalNotification
  3637.  
  3638.     Input Parameters:    
  3639.         
  3640.     Output Parameters:
  3641.         
  3642.     Description:
  3643.         release any allocated storage
  3644.         remove DRVRs from the UnitTable
  3645.  
  3646.         One small complication happens when the USS-720 cable is used. It's possible
  3647.         that the user has the device plugged in, but the printer wasn't powered on.
  3648.         In this case, our state machine is still cycling between the states 
  3649.         kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
  3650.         returns we'll crash the system. We monitor terminating to handle this
  3651.         
  3652.  
  3653.  
  3654.  
  3655.  
  3656.  
  3657.  
  3658.  
  3659.  
  3660.  
  3661.  
  3662. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3663. OSStatus
  3664. PrinterRemovalNotification( void )
  3665. {
  3666. static    Boolean    logfileclosed = false;
  3667. static    Boolean    aborted = false;
  3668. static    Boolean    deregistered = false;
  3669. static    Boolean    readpipeaborted = false;
  3670. static    Boolean    writepipeaborted = false;
  3671. static    Boolean    timedout = false;
  3672. OSStatus            result = noErr;
  3673. static unsigned long    tc = 0;
  3674.     //
  3675.     //    notify state machine not to continue
  3676.     //
  3677.     printerClassRecord.terminating = true;
  3678.     
  3679.     MyUSBExpertStatusLevel(kNormalStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Driver removal notification received", 0);
  3680.     if (!logfileclosed)
  3681.     {
  3682.         MyUSBExpertStatusLevel(kNormalStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Closing printer log file", 0);
  3683.         LOGGING( fclose( logfile ) );
  3684.         logfileclosed = true;
  3685.     }
  3686.     
  3687.     // if the printer was never registered, then don't try to deregister it
  3688.     if (!(printerClassRecord.printerRegistered))
  3689.         deregistered = true;
  3690.         
  3691.     if (!deregistered)    
  3692.     {
  3693.         //
  3694.         //    remove printer from the name registry
  3695.         //
  3696.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Removed printer entry from nameregistry", 0);
  3697.         DeregisterDevice( &printerClassRecord );
  3698.         deregistered = true;
  3699.     }
  3700.  
  3701.     // per the Mac OS USB DDK API Ref 
  3702.     // "If the device associated with this call [USBDelay] is unplugged and its driver removed while
  3703.     //  this function call is pending, the function will not complete."
  3704.     // therefore don't hang around if a delay is in progress
  3705.     if (( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL ) && (!printerClassRecord.delayInProgress))
  3706.     {
  3707.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Waiting for configuration to complete", printerClassRecord.pb.usbRefcon);
  3708.         return (OSStatus) kUSBDeviceBusy;
  3709.     }
  3710.     
  3711.     // Abort any outstanding write requests
  3712.     if (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL ) && (!writepipeaborted))
  3713.     {
  3714.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Abort write pipe", printerClassRecord.writePipeRef);
  3715.         USBAbortPipeByReference( printerClassRecord.writePipeRef );
  3716.         writepipeaborted = true;
  3717.         return (OSStatus) kUSBDeviceBusy;
  3718.     }
  3719.     
  3720.     // Abort any outstanding read requests
  3721.     if (( printerClassRecord.in.usbCompletion != (USBCompletion) NULL ) && (!readpipeaborted))
  3722.     {
  3723.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Abort read pipe", printerClassRecord.readPipeRef );
  3724.         USBAbortPipeByReference( printerClassRecord.readPipeRef );
  3725.         readpipeaborted = true;
  3726.         return (OSStatus) kUSBDeviceBusy;
  3727.     }
  3728.     
  3729.     // Abort any outstanding transactions
  3730.     if (!aborted)
  3731.     {
  3732.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Call Abort()", 0);
  3733.         Abort( 0, &printerClassRecord );
  3734.         aborted = true;
  3735.     }
  3736.  
  3737.     // wait up to ten seconds for the read & write routines to complete.  When they do, the completion procptrs will be NULL'd
  3738.     if (tc == 0)
  3739.         tc = TickCount() + 10*60;
  3740.         
  3741.     if ( TickCount() >= tc )
  3742.         timedout = true;
  3743.         
  3744.     if (( TickCount() < tc ) &&
  3745.          (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL) ||
  3746.           ( printerClassRecord.in.usbCompletion != (USBCompletion) NULL )))
  3747.     {
  3748.         return (OSStatus) kUSBDeviceBusy;
  3749.     }
  3750.     
  3751.     // Put the appropriate timeout message in the log
  3752.     if ( timedout )
  3753.     {
  3754.         MyUSBExpertStatusLevel(kNormalStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"took longer than 10 seconds for read/write pipes to complete", 0);
  3755.     }
  3756.     else
  3757.     {
  3758.         MyUSBExpertStatusLevel(kNormalStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Pipes closed normally", 0);
  3759.     }
  3760.     
  3761.     if (( printerClassRecord.out.usbCompletion != (USBCompletion) NULL) ||
  3762.           ( printerClassRecord.in.usbCompletion != (USBCompletion) NULL ))
  3763.     {
  3764.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Completion procs are not nil!!", 0);
  3765.     }
  3766.     
  3767.     // remove our unit table drivers
  3768.     if (printerClassRecord.outRefNum != -1 )
  3769.     {
  3770.         TradRemoveDriver( printerClassRecord.outRefNum, false );
  3771.         printerClassRecord.outRefNum = -1;
  3772.     }
  3773.     
  3774.     if (printerClassRecord.inRefNum != -1 )
  3775.     {
  3776.         TradRemoveDriver( printerClassRecord.inRefNum, false );
  3777.         printerClassRecord.inRefNum = -1;
  3778.     }
  3779.  
  3780.     //
  3781.     //    release any allocated storage
  3782.     //
  3783.     if ( printerClassRecord.pCapabilityString != printerClassRecord.capability )
  3784.     {
  3785.         MyUSBExpertStatusLevel(kDebugStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Deallocated capability string memory", 0);
  3786.         printerClassRecord.pb.usbReference = printerClassRecord.deviceRef;             
  3787.         printerClassRecord.pb.usbFlags = 0;             
  3788.         printerClassRecord.pb.usbRefcon = kDeallocateCapbilityString;             
  3789.         printerClassRecord.pb.usbBuffer = printerClassRecord.pCapabilityString;        
  3790.         printerClassRecord.pb.usbCompletion = (USBCompletion)kUSBNoCallBack;
  3791.         printerClassRecord.delayInProgress = true;        // this prevents the control pipe completion procptr from being checked
  3792.         USBDeallocMem(&printerClassRecord.pb);
  3793.         
  3794.         printerClassRecord.pCapabilityString = printerClassRecord.capability;
  3795.         return (OSStatus) kUSBDeviceBusy;
  3796.     }
  3797.  
  3798.     //
  3799.     //    don't need to hang on to param blocks after we've gone away
  3800.     //
  3801.     UnholdMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  3802.  
  3803.     MyUSBExpertStatusLevel(kNormalStatusLevel, printerClassRecord.deviceRef, kPStrPrinterDriverName"Ready for removal", 0);
  3804.     return kUSBNoErr;
  3805. }
  3806.  
  3807. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3808.     Name:        CFMInitialization
  3809.  
  3810.     Input Parameters:    
  3811.         initBlock
  3812.         
  3813.     Output Parameters:
  3814.         printerClassDriverFileSpec        set global
  3815.         
  3816.     Description:
  3817.         We use the code fragment initialization to get our filespec which 
  3818.         LoadResources will use to open our resource fork.
  3819.         
  3820.         A peculiarity of the USB 1.0 implementation is that does not lock the
  3821.         driver into physical memory. As a result a driver which does not call
  3822.         SetDriverClosureMemory on it's fragment will likely be paged in during
  3823.         interrupt time and a double bus-fault will occur. The solution for this
  3824.         is to have the USB Expert call SetDriverClosureMemory in a future release
  3825.         of the USB stack. In the meantime, we call it on ourselves to lock us into
  3826.         physical memory. When the USB stack is revved, one call to SetDriverClosureMemory
  3827.         (either this one or the Expert's) will be treated as a NOP.
  3828.  
  3829.  
  3830.  
  3831.  
  3832. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3833. OSErr
  3834. CFMInitialization( CFragInitBlock *initBlock )
  3835. {
  3836.     //
  3837.     //    get a reference to our file so that we can open up the resource fork later on
  3838.     //
  3839.     if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
  3840.         printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
  3841.  
  3842.     return noErr;
  3843.  
  3844. }
  3845.  
  3846. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  3847.     Name:        MyUSBExpertStatusLevel
  3848.  
  3849.     Input Parameters:    
  3850.         level        value 1 - 5 of the status level for the message.  Refer to use in 
  3851.                         USBExpertStatusLevel call
  3852.         ref            device or interface reference associated with the message
  3853.         status        Pascal style string status message to log
  3854.         value        value to store along with status message.
  3855.         
  3856.     Output Parameters:
  3857.         returns a result of osstatus
  3858.         
  3859.     Description:
  3860.         MyUSBExpertStatusLevel checks the version of USB present and makes the 
  3861.         USBExpertStatusLevel call if USB 1.2 or later is present or uses the 
  3862.         USBExpertStatus call instead if USB 1.0 - 1.1 is present.  This requires 
  3863.         the one weak link with the USBServicesLib library file.
  3864.  
  3865.  
  3866. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  3867. OSStatus MyUSBExpertStatusLevel(UInt32 level, USBDeviceRef ref, StringPtr status, UInt32 value)
  3868. {
  3869.     OSStatus result;
  3870.     
  3871.     if (gUSBVersion < kUSBv12)
  3872.     {
  3873.         result = USBExpertStatus(ref, status, value);
  3874.     }
  3875.     else
  3876.     {
  3877.         result = USBExpertStatusLevel(level, ref, status, value);
  3878.     }
  3879.     
  3880.     return result;
  3881. }
  3882.  
  3883.  
  3884.  
  3885. // eof
  3886.